static bool parse_block_into(parser_t *parser, ast_block *block);
static bool parse_statement_or_block(parser_t *parser, ast_expression **out);
static bool parse_statement(parser_t *parser, ast_block *block, ast_expression **out, bool allow_cases);
-static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue);
-static ast_expression* parse_expression(parser_t *parser, bool stopatcomma);
+static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels);
+static ast_expression* parse_expression(parser_t *parser, bool stopatcomma, bool with_labels);
static void parseerror(parser_t *parser, const char *fmt, ...)
{
return ( ast_expression*)util_htget(parser->htfields, name);
}
-static ast_expression* parser_find_label(parser_t *parser, const char *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];
}
}
-static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue)
+static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels)
{
ast_expression *expr = NULL;
shunt sy;
parseerror(parser, "namespace for member not found");
goto onerr;
}
- 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));
} 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 && with_labels) {
+ var = (ast_expression*)parser_find_label(parser, parser_tokval(parser));
+ if (!with_labels) {
+ ast_label *lbl = ast_label_new(parser_ctx(parser), parser_tokval(parser), true);
+ var = (ast_expression*)lbl;
+ vec_push(parser->labels, lbl);
+ }
}
if (!var) {
/* intrinsics */
return NULL;
}
-static ast_expression* parse_expression(parser_t *parser, bool stopatcomma)
+static ast_expression* parse_expression(parser_t *parser, bool stopatcomma, bool with_labels)
{
- ast_expression *e = parse_expression_leave(parser, stopatcomma, false);
+ ast_expression *e = parse_expression_leave(parser, stopatcomma, false, with_labels);
if (!e)
return NULL;
if (!parser_next(parser)) {
return false;
}
/* parse the condition */
- cond = parse_expression_leave(parser, false, true);
+ cond = parse_expression_leave(parser, false, true, false);
if (!cond)
return false;
/* closing paren */
return false;
}
/* parse the condition */
- cond = parse_expression_leave(parser, false, true);
+ cond = parse_expression_leave(parser, false, true, false);
if (!cond)
return false;
/* closing paren */
return false;
}
/* parse the condition */
- cond = parse_expression_leave(parser, false, true);
+ cond = parse_expression_leave(parser, false, true, false);
if (!cond)
return false;
/* closing paren */
}
else if (parser->tok != ';')
{
- initexpr = parse_expression_leave(parser, false, false);
+ initexpr = parse_expression_leave(parser, false, false, false);
if (!initexpr)
goto onerr;
}
/* parse the condition */
if (parser->tok != ';') {
- cond = parse_expression_leave(parser, false, true);
+ cond = parse_expression_leave(parser, false, true, false);
if (!cond)
goto onerr;
}
/* parse the incrementor */
if (parser->tok != ')') {
- increment = parse_expression_leave(parser, false, false);
+ increment = parse_expression_leave(parser, false, false, false);
if (!increment)
goto onerr;
if (!ast_side_effects(increment)) {
}
if (parser->tok != ';') {
- exp = parse_expression(parser, false);
+ exp = parse_expression(parser, false, false);
if (!exp)
return false;
return false;
}
/* parse the operand */
- operand = parse_expression_leave(parser, false, false);
+ operand = parse_expression_leave(parser, false, false, false);
if (!operand)
return false;
parseerror(parser, "expected expression for case");
return false;
}
- swcase.value = parse_expression_leave(parser, false, false);
+ swcase.value = parse_expression_leave(parser, false, false, false);
if (!swcase.value) {
ast_delete(switchnode);
parseerror(parser, "expected expression for case");
static bool parse_goto(parser_t *parser, ast_expression **out)
{
- size_t i;
- ast_goto *gt = NULL;
+ ast_goto *gt = NULL;
+ ast_expression *lbl;
if (!parser_next(parser))
return false;
}
/* failed to parse expression for goto */
- if (!(expression = parse_expression(parser, false)) ||
+ if (!(expression = parse_expression(parser, false, true)) ||
!(*out = parse_goto_computed(parser, expression))) {
parseerror(parser, "invalid goto expression");
ast_unref(expression);
/* not computed goto */
gt = ast_goto_new(parser_ctx(parser), parser_tokval(parser));
-
- for (i = 0; i < vec_size(parser->labels); ++i) {
- if (!strcmp(parser->labels[i]->name, parser_tokval(parser))) {
- ast_goto_set_label(gt, parser->labels[i]);
- break;
+ lbl = parser_find_label(parser, gt->name);
+ if (lbl) {
+ if (!ast_istype(lbl, ast_label)) {
+ parseerror(parser, "internal error: label is not an ast_label");
+ ast_delete(gt);
+ return false;
}
+ ast_goto_set_label(gt, (ast_label*)lbl);
}
- if (i == vec_size(parser->labels))
+ else
vec_push(parser->gotos, gt);
if (!parser_next(parser) || parser->tok != ';') {
parseerror(parser, "label must be an identifier");
return false;
}
- label = ast_label_new(parser_ctx(parser), parser_tokval(parser));
- if (!label)
- return false;
- vec_push(parser->labels, label);
+ label = (ast_label*)parser_find_label(parser, parser_tokval(parser));
+ if (label) {
+ if (!label->undefined) {
+ parseerror(parser, "label `%s` already defined", label->name);
+ return false;
+ }
+ label->undefined = false;
+ }
+ else {
+ label = ast_label_new(parser_ctx(parser), parser_tokval(parser), false);
+ vec_push(parser->labels, label);
+ }
*out = (ast_expression*)label;
if (!parser_next(parser)) {
parseerror(parser, "parse error after label");
}
else
{
- ast_expression *exp = parse_expression(parser, false);
+ ast_expression *exp = parse_expression(parser, false, false);
if (!exp)
return false;
*out = exp;
if (!parser_next(parser))
return false;
- framenum = parse_expression_leave(parser, true, false);
+ framenum = parse_expression_leave(parser, true, false, false);
if (!framenum) {
parseerror(parser, "expected a framenumber constant in[frame,think] notation");
return false;
nextthink = (ast_expression*)thinkfunc;
} else {
- nextthink = parse_expression_leave(parser, true, false);
+ nextthink = parse_expression_leave(parser, true, false, false);
if (!nextthink) {
ast_unref(framenum);
parseerror(parser, "expected a think-function in [frame,think] notation");
return NULL;
}
- cexp = parse_expression_leave(parser, true, false);
+ cexp = parse_expression_leave(parser, true, false, false);
if (!cexp || !ast_istype(cexp, ast_value)) {
if (cexp)
ast_expression *cexp;
ast_value *cval;
- cexp = parse_expression_leave(parser, true, false);
+ cexp = parse_expression_leave(parser, true, false, false);
if (!cexp)
break;