[qfcc] Add support for named labels in statements

Yeah, I've finally decided to implement goto. Limited to function scope
of course.
This commit is contained in:
Bill Currie 2020-03-11 11:31:54 +09:00
parent d5560434c0
commit 1cd5ea5732
5 changed files with 45 additions and 1 deletions

View file

@ -290,6 +290,19 @@ const char *new_label_name (void);
*/
expr_t *new_label_expr (void);
/** Create a named label expression node.
The label name is set using new_label_name(), but the symbol is used to add
the label to the function's label scope symbol table. If the label already
exists in the function's label scope, then the existing label is returned,
allowing for forward label declarations.
\param label The name symbol to use for adding the label to the function
label scope.
\return The new label expression (::ex_label_t) node.
*/
expr_t *named_label_expr (struct symbol_s *label);
/** Create a new label reference expression node.
Used for taking the address of a label (eg. jump tables).

View file

@ -79,6 +79,7 @@ typedef struct function_s {
scope symbol table's defspace.
*/
struct symtab_s *symtab;
struct symtab_s *label_scope;
struct reloc_s *refs; ///< relocation targets for this function
struct expr_s *var_init;
const char *name; ///< nice name for __PRETTY_FUNCTION__

View file

@ -495,6 +495,27 @@ new_label_expr (void)
return l;
}
expr_t *
named_label_expr (symbol_t *label)
{
symbol_t *sym;
if (!current_func) {
// XXX this might be only an error
internal_error (0, "label defined outside of function scope");
}
sym = symtab_lookup (current_func->label_scope, label->name);
if (sym) {
return sym->s.expr;
}
label->sy_type = sy_expr;
label->s.expr = new_label_expr ();
symtab_addsymbol (current_func->label_scope, label);
return label->s.expr;
}
expr_t *
new_label_ref (ex_label_t *label)
{

View file

@ -493,6 +493,7 @@ build_scope (symbol_t *fsym, symtab_t *parent)
symtab = new_symtab (parent, stab_local);
fsym->s.func->symtab = symtab;
fsym->s.func->label_scope = new_symtab (0, stab_local);
symtab->space = defspace_new (ds_virtual);
current_symtab = symtab;

View file

@ -188,7 +188,7 @@ int yylex (void);
%type <expr> unary_expr ident_expr cast_expr opt_arg_list arg_list
%type <expr> init_var_decl_list init_var_decl
%type <switch_block> switch_block
%type <symbol> identifier
%type <symbol> identifier label
%type <symbol> overloaded_identifier
@ -1292,6 +1292,10 @@ statement
else
error (0, "continue outside of loop");
}
| label
{
$$ = named_label_expr ($1);
}
| CASE expr ':'
{
$$ = case_label_expr (switch_block, $2);
@ -1358,6 +1362,10 @@ else
}
;
label
: NAME ':'
;
bool_label
: /* empty */
{