/*
- * Copyright (C) 2012
+ * Copyright (C) 2012, 2013
* Wolfgang Bumiller
* Dale Weiler
*
#include "gmqcc.h"
#include "lexer.h"
+#include "ast.h"
/* beginning of locals */
#define PARSER_HT_LOCALS 2
return ( ast_expression*)util_htget(parser->htfields, name);
}
+static ast_expression* parser_find_label(parser_t *parser, const char *name) {
+ size_t i;
+ if (!parser->labels)
+ return NULL;
+
+ for(i = 0; i < vec_size(parser->labels); i++)
+ if (!strcmp(parser->labels[i]->name, name))
+ return (ast_expression*)parser->labels[i];
+ return NULL;
+}
+
static ast_expression* parser_find_global(parser_t *parser, const char *name)
{
return (ast_expression*)util_htget(parser->htglobals, name);
parseerror(parser, "namespace for member not found");
goto onerr;
}
- else
- var = parser_find_var(parser, parser_tokval(parser));
+ else if (!(var = parser_find_var(parser, parser_tokval(parser))))
+ var = (ast_expression*)parser_find_label(parser, parser_tokval(parser));
} else {
var = parser_find_var(parser, parser_tokval(parser));
if (!var)
var = parser_find_field(parser, parser_tokval(parser));
+ if (!var)
+ var = parser_find_label(parser, parser_tokval(parser));
}
if (!var) {
/* intrinsics */
if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) {
var = (ast_expression*)intrinsic_debug_typestring;
-
}
else
{
typevar = parser_find_typedef(parser, parser_tokval(parser), 0);
if (typevar || parser->tok == TOKEN_TYPENAME) {
+#if 0
if (opts.standard != COMPILER_GMQCC) {
if (parsewarning(parser, WARN_EXTENSIONS,
"current standard does not allow variable declarations in for-loop initializers"))
goto onerr;
}
+#endif
if (!parse_variable(parser, block, true, CV_VAR, typevar, false, false, 0, NULL))
goto onerr;
}
if (!parser_next(parser))
parseerror(parser, "parse error");
if (expected->expression.next->expression.vtype != TYPE_VOID) {
- if (opts.standard != COMPILER_GMQCC)
- (void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value");
- else
- parseerror(parser, "return without value");
+ (void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value");
}
ret = ast_return_new(ctx, NULL);
}
return true;
}
+/* parse computed goto sides */
+static ast_expression *parse_goto_computed(parser_t *parser, ast_expression *side) {
+ ast_expression *on_true;
+ ast_expression *on_false;
+
+ if (!side)
+ return NULL;
+
+ if (ast_istype(side, ast_ternary)) {
+ on_true = parse_goto_computed(parser, ((ast_ternary*)side)->on_true);
+ on_false = parse_goto_computed(parser, ((ast_ternary*)side)->on_false);
+
+ return (ast_expression*)ast_ifthen_new(parser_ctx(parser), ((ast_ternary*)side)->cond, on_true, on_false);
+ } else if (ast_istype(side, ast_label)) {
+ ast_goto *gt = ast_goto_new(parser_ctx(parser), ((ast_label*)side)->name);
+ ast_goto_set_label(gt, ((ast_label*)side));
+ return (ast_expression*)gt;
+ }
+ return NULL;
+}
+
static bool parse_goto(parser_t *parser, ast_expression **out)
{
size_t i;
- ast_goto *gt;
+ ast_goto *gt = NULL;
- if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
- parseerror(parser, "expected label name after `goto`");
+ if (!parser_next(parser))
return false;
+
+ if (parser->tok != TOKEN_IDENT) {
+ ast_expression *expression;
+ /* could be an expression i.e computed goto :-) */
+ if (parser->tok != '(') {
+ parseerror(parser, "expected label name after `goto`");
+ return false;
+ }
+
+ /* failed to parse expression for goto */
+ if (!(expression = parse_expression(parser, false)))
+ return false;
+
+ if (!(*out = parse_goto_computed(parser, expression)))
+ return false;
+
+ return true;
}
+ /* not computed goto */
gt = ast_goto_new(parser_ctx(parser), parser_tokval(parser));
for (i = 0; i < vec_size(parser->labels); ++i) {
{
/* other globals */
if (old) {
- if (opts.standard == COMPILER_GMQCC) {
- parseerror(parser, "global `%s` already declared here: %s:%i",
- var->name, ast_ctx(old).file, ast_ctx(old).line);
+ if (parsewarning(parser, WARN_DOUBLE_DECLARATION,
+ "global `%s` already declared here: %s:%i",
+ var->name, ast_ctx(old).file, ast_ctx(old).line))
+ {
retval = false;
goto cleanup;
- } else {
- if (parsewarning(parser, WARN_DOUBLE_DECLARATION,
- "global `%s` already declared here: %s:%i",
- var->name, ast_ctx(old).file, ast_ctx(old).line))
- {
- retval = false;
- goto cleanup;
- }
- proto = (ast_value*)old;
- if (!ast_istype(old, ast_value)) {
- parseerror(parser, "internal error: not an ast_value");
- retval = false;
- proto = NULL;
- goto cleanup;
- }
- if (!parser_check_qualifiers(parser, var, proto)) {
- retval = false;
- proto = NULL;
- goto cleanup;
- }
- proto->expression.flags |= var->expression.flags;
- ast_delete(var);
- var = proto;
}
+ proto = (ast_value*)old;
+ if (!ast_istype(old, ast_value)) {
+ parseerror(parser, "internal error: not an ast_value");
+ retval = false;
+ proto = NULL;
+ goto cleanup;
+ }
+ if (!parser_check_qualifiers(parser, var, proto)) {
+ retval = false;
+ proto = NULL;
+ goto cleanup;
+ }
+ proto->expression.flags |= var->expression.flags;
+ ast_delete(var);
+ var = proto;
}
if (opts.standard == COMPILER_QCC &&
(old = parser_find_field(parser, var->name)))
}
else
{
- if (opts.standard != COMPILER_GMQCC &&
- !OPTS_FLAG(INITIALIZED_NONCONSTANTS) &&
+ if (!OPTS_FLAG(INITIALIZED_NONCONSTANTS) &&
qualifier != CV_VAR)
{
var->cvq = CV_CONST;