static bool parser_variable(parser_t *parser, ast_block *localblock);
static ast_block* parser_parse_block(parser_t *parser);
static ast_expression* parser_parse_statement_or_block(parser_t *parser);
-static ast_expression* parser_expression_leave(parser_t *parser);
-static ast_expression* parser_expression(parser_t *parser);
+static ast_expression* parser_expression_leave(parser_t *parser, bool stopatcomma);
+static ast_expression* parser_expression(parser_t *parser, bool stopatcomma);
void parseerror(parser_t *parser, const char *fmt, ...)
{
return true;
}
-static ast_expression* parser_expression_leave(parser_t *parser)
+static ast_expression* parser_expression_leave(parser_t *parser, bool stopatcomma)
{
ast_expression *expr = NULL;
shunt sy;
}
/* found an operator */
op = &operators[o];
+
+ /* when declaring variables, a comma starts a new variable */
+ if (op->id == opid1(',') && !parens && stopatcomma)
+ break;
+
if (op->id == opid1('.')) {
/* for gmqcc standard: open up the namespace of the previous type */
ast_expression *prevex = sy.out[sy.out_count-1].out;
return NULL;
}
-static ast_expression* parser_expression(parser_t *parser)
+static ast_expression* parser_expression(parser_t *parser, bool stopatcomma)
{
- ast_expression *e = parser_expression_leave(parser);
+ ast_expression *e = parser_expression_leave(parser, stopatcomma);
if (!e)
return NULL;
if (!parser_next(parser)) {
return false;
}
/* parse the condition */
- cond = parser_expression_leave(parser);
+ cond = parser_expression_leave(parser, false);
if (!cond)
return false;
/* closing paren */
return false;
}
/* parse the condition */
- cond = parser_expression_leave(parser);
+ cond = parser_expression_leave(parser, false);
if (!cond)
return false;
/* closing paren */
return false;
}
/* parse the condition */
- cond = parser_expression_leave(parser);
+ cond = parser_expression_leave(parser, false);
if (!cond)
return false;
/* closing paren */
}
else if (parser->tok != ';')
{
- initexpr = parser_expression_leave(parser);
+ initexpr = parser_expression_leave(parser, false);
if (!initexpr)
goto onerr;
}
/* parse the condition */
if (parser->tok != ';') {
- cond = parser_expression_leave(parser);
+ cond = parser_expression_leave(parser, false);
if (!cond)
goto onerr;
}
/* parse the incrementor */
if (parser->tok != ')') {
- increment = parser_expression_leave(parser);
+ increment = parser_expression_leave(parser, false);
if (!increment)
goto onerr;
}
}
if (parser->tok != ';') {
- exp = parser_expression(parser);
+ exp = parser_expression(parser, false);
if (!exp)
return false;
}
else
{
- ast_expression *exp = parser_expression(parser);
+ ast_expression *exp = parser_expression(parser, false);
if (!exp)
return false;
*out = exp;
}
func->builtin = -parser_token(parser)->constval.i;
+
+ if (!parser_next(parser))
+ return false;
} else if (parser->tok == '{') {
/* function body */
ast_block *block;
parseerror(parser, "missing semicolon after function body (mandatory with -std=qcc)");
return true;
} else {
- parseerror(parser, "TODO, const assignment");
- }
+ ast_expression *cexp;
+ ast_value *cval;
- if (!parser_next(parser))
- return false;
+ cexp = parser_expression_leave(parser, true);
+ cval = (ast_value*)cexp;
+ if (!ast_istype(cval, ast_value) || !cval->isconst)
+ parseerror(parser, "cannot initialize a global constant variable with a non-constant expression");
+ else
+ {
+ var->isconst = true;
+ memcpy(&var->constval, &cval->constval, sizeof(var->constval));
+ memset(&cval->constval, 0, sizeof(cval->constval));
+ ast_unref(cval);
+ }
+ }
if (parser->tok == ',') {
/* another */
}
if (parser->tok != ';') {
- parseerror(parser, "expected semicolon");
+ parseerror(parser, "missing semicolon");
return false;
}