mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-01-18 22:31:36 +00:00
parse_expression now takes a boolean flag on whether or not it should be creating ast_labels for undefined identifiers; creating the label later will pick it up and set its undefined flag to false
This commit is contained in:
parent
0ab15e9f22
commit
e146fd121c
3 changed files with 67 additions and 45 deletions
14
ast.c
14
ast.c
|
@ -826,14 +826,15 @@ void ast_switch_delete(ast_switch *self)
|
|||
mem_d(self);
|
||||
}
|
||||
|
||||
ast_label* ast_label_new(lex_ctx ctx, const char *name)
|
||||
ast_label* ast_label_new(lex_ctx ctx, const char *name, bool undefined)
|
||||
{
|
||||
ast_instantiate(ast_label, ctx, ast_label_delete);
|
||||
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_label_codegen);
|
||||
|
||||
self->name = util_strdup(name);
|
||||
self->irblock = NULL;
|
||||
self->gotos = NULL;
|
||||
self->name = util_strdup(name);
|
||||
self->irblock = NULL;
|
||||
self->gotos = NULL;
|
||||
self->undefined = undefined;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -2868,6 +2869,11 @@ bool ast_label_codegen(ast_label *self, ast_function *func, bool lvalue, ir_valu
|
|||
size_t i;
|
||||
ir_value *dummy;
|
||||
|
||||
if (self->undefined) {
|
||||
compile_error(ast_ctx(self), "internal error: ast_label never defined");
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = NULL;
|
||||
if (lvalue) {
|
||||
compile_error(ast_ctx(self), "internal error: ast_label cannot be an lvalue");
|
||||
|
|
4
ast.h
4
ast.h
|
@ -525,9 +525,11 @@ struct ast_label_s
|
|||
const char *name;
|
||||
ir_block *irblock;
|
||||
ast_goto **gotos;
|
||||
/* means it has not yet been defined */
|
||||
bool undefined;
|
||||
};
|
||||
|
||||
ast_label* ast_label_new(lex_ctx ctx, const char *name);
|
||||
ast_label* ast_label_new(lex_ctx ctx, const char *name, bool undefined);
|
||||
void ast_label_delete(ast_label*);
|
||||
void ast_label_register_goto(ast_label*, ast_goto*);
|
||||
|
||||
|
|
94
parser.c
94
parser.c
|
@ -111,8 +111,8 @@ static ast_block* parse_block(parser_t *parser);
|
|||
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, ...)
|
||||
{
|
||||
|
@ -300,11 +300,9 @@ static ast_expression* parser_find_field(parser_t *parser, const char *name)
|
|||
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];
|
||||
|
@ -1494,7 +1492,7 @@ static void parser_reclassify_token(parser_t *parser)
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -1584,14 +1582,20 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
|
|||
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 */
|
||||
|
@ -1920,9 +1924,9 @@ onerr:
|
|||
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)) {
|
||||
|
@ -2072,7 +2076,7 @@ static bool parse_if(parser_t *parser, ast_block *block, ast_expression **out)
|
|||
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 */
|
||||
|
@ -2193,7 +2197,7 @@ static bool parse_while_go(parser_t *parser, ast_block *block, ast_expression **
|
|||
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 */
|
||||
|
@ -2308,7 +2312,7 @@ static bool parse_dowhile_go(parser_t *parser, ast_block *block, ast_expression
|
|||
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 */
|
||||
|
@ -2437,7 +2441,7 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou
|
|||
}
|
||||
else if (parser->tok != ';')
|
||||
{
|
||||
initexpr = parse_expression_leave(parser, false, false);
|
||||
initexpr = parse_expression_leave(parser, false, false, false);
|
||||
if (!initexpr)
|
||||
goto onerr;
|
||||
}
|
||||
|
@ -2454,7 +2458,7 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou
|
|||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -2471,7 +2475,7 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou
|
|||
|
||||
/* 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)) {
|
||||
|
@ -2528,7 +2532,7 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou
|
|||
}
|
||||
|
||||
if (parser->tok != ';') {
|
||||
exp = parse_expression(parser, false);
|
||||
exp = parse_expression(parser, false, false);
|
||||
if (!exp)
|
||||
return false;
|
||||
|
||||
|
@ -2814,7 +2818,7 @@ static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression *
|
|||
return false;
|
||||
}
|
||||
/* parse the operand */
|
||||
operand = parse_expression_leave(parser, false, false);
|
||||
operand = parse_expression_leave(parser, false, false, false);
|
||||
if (!operand)
|
||||
return false;
|
||||
|
||||
|
@ -2878,7 +2882,7 @@ static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression *
|
|||
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");
|
||||
|
@ -2999,8 +3003,8 @@ static ast_expression *parse_goto_computed(parser_t *parser, ast_expression *sid
|
|||
|
||||
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;
|
||||
|
@ -3015,7 +3019,7 @@ static bool parse_goto(parser_t *parser, ast_expression **out)
|
|||
}
|
||||
|
||||
/* 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);
|
||||
|
@ -3027,14 +3031,16 @@ static bool parse_goto(parser_t *parser, ast_expression **out)
|
|||
|
||||
/* 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 != ';') {
|
||||
|
@ -3269,10 +3275,18 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression *
|
|||
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");
|
||||
|
@ -3297,7 +3311,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression *
|
|||
}
|
||||
else
|
||||
{
|
||||
ast_expression *exp = parse_expression(parser, false);
|
||||
ast_expression *exp = parse_expression(parser, false, false);
|
||||
if (!exp)
|
||||
return false;
|
||||
*out = exp;
|
||||
|
@ -3458,7 +3472,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
|
|||
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;
|
||||
|
@ -3506,7 +3520,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
|
|||
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");
|
||||
|
@ -4172,7 +4186,7 @@ static ast_value *parse_arraysize(parser_t *parser, ast_value *var)
|
|||
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)
|
||||
|
@ -4938,7 +4952,7 @@ skipvar:
|
|||
ast_expression *cexp;
|
||||
ast_value *cval;
|
||||
|
||||
cexp = parse_expression_leave(parser, true, false);
|
||||
cexp = parse_expression_leave(parser, true, false, false);
|
||||
if (!cexp)
|
||||
break;
|
||||
|
||||
|
|
Loading…
Reference in a new issue