parsing of loop labels

This commit is contained in:
Wolfgang Bumiller 2012-12-27 23:43:20 +01:00
parent c6e7e80f23
commit ebb7cb2ae3
4 changed files with 185 additions and 17 deletions

3
ast.c
View file

@ -764,12 +764,13 @@ void ast_loop_delete(ast_loop *self)
mem_d(self);
}
ast_breakcont* ast_breakcont_new(lex_ctx ctx, bool iscont)
ast_breakcont* ast_breakcont_new(lex_ctx ctx, bool iscont, unsigned int levels)
{
ast_instantiate(ast_breakcont, ctx, ast_breakcont_delete);
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_breakcont_codegen);
self->is_continue = iscont;
self->levels = levels;
return self;
}

5
ast.h
View file

@ -474,9 +474,10 @@ bool ast_loop_codegen(ast_loop*, ast_function*, bool lvalue, ir_value**);
struct ast_breakcont_s
{
ast_expression_common expression;
bool is_continue;
bool is_continue;
unsigned int levels;
};
ast_breakcont* ast_breakcont_new(lex_ctx ctx, bool iscont);
ast_breakcont* ast_breakcont_new(lex_ctx ctx, bool iscont, unsigned int levels);
void ast_breakcont_delete(ast_breakcont*);
bool ast_breakcont_codegen(ast_breakcont*, ast_function*, bool lvalue, ir_value**);

View file

@ -45,6 +45,7 @@
GMQCC_DEFINE_FLAG(FALSE_EMPTY_STRINGS)
GMQCC_DEFINE_FLAG(UTF8)
GMQCC_DEFINE_FLAG(BAIL_ON_WERROR)
GMQCC_DEFINE_FLAG(LOOP_LABELS)
#endif
/* warning flags */

193
parser.c
View file

@ -60,8 +60,9 @@ typedef struct {
/* All the labels the function defined...
* Should they be in ast_function instead?
*/
ast_label **labels;
ast_goto **gotos;
ast_label **labels;
ast_goto **gotos;
const char **loops;
/* A list of hashtables for each scope */
ht *variables;
@ -2018,7 +2019,58 @@ static bool parse_if(parser_t *parser, ast_block *block, ast_expression **out)
return true;
}
static bool parse_while_go(parser_t *parser, ast_block *block, ast_expression **out);
static bool parse_while(parser_t *parser, ast_block *block, ast_expression **out)
{
bool rv;
char *label = NULL;
/* skip the 'while' and get the body */
if (!parser_next(parser)) {
if (OPTS_FLAG(LOOP_LABELS))
parseerror(parser, "expected loop label or 'while' condition in parenthesis");
else
parseerror(parser, "expected 'while' condition in parenthesis");
return false;
}
if (parser->tok == ':') {
if (!OPTS_FLAG(LOOP_LABELS))
parseerror(parser, "labeled loops not activated, try using -floop-labels");
if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
parseerror(parser, "expected loop label");
return false;
}
label = util_strdup(parser_tokval(parser));
if (!parser_next(parser)) {
mem_d(label);
parseerror(parser, "expected 'while' condition in parenthesis");
return false;
}
}
if (parser->tok != '(') {
parseerror(parser, "expected 'while' condition in parenthesis");
return false;
}
vec_push(parser->loops, label);
rv = parse_while_go(parser, block, out);
if (label)
mem_d(label);
if (vec_last(parser->loops) != label) {
parseerror(parser, "internal error: label stack corrupted");
rv = false;
ast_delete(*out);
*out = NULL;
}
else
vec_pop(parser->loops);
return rv;
}
static bool parse_while_go(parser_t *parser, ast_block *block, ast_expression **out)
{
ast_loop *aloop;
ast_expression *cond, *ontrue;
@ -2070,7 +2122,53 @@ static bool parse_while(parser_t *parser, ast_block *block, ast_expression **out
return true;
}
static bool parse_dowhile_go(parser_t *parser, ast_block *block, ast_expression **out);
static bool parse_dowhile(parser_t *parser, ast_block *block, ast_expression **out)
{
bool rv;
char *label = NULL;
/* skip the 'do' and get the body */
if (!parser_next(parser)) {
if (OPTS_FLAG(LOOP_LABELS))
parseerror(parser, "expected loop label or body");
else
parseerror(parser, "expected loop body");
return false;
}
if (parser->tok == ':') {
if (!OPTS_FLAG(LOOP_LABELS))
parseerror(parser, "labeled loops not activated, try using -floop-labels");
if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
parseerror(parser, "expected loop label");
return false;
}
label = util_strdup(parser_tokval(parser));
if (!parser_next(parser)) {
mem_d(label);
parseerror(parser, "expected loop body");
return false;
}
}
vec_push(parser->loops, label);
rv = parse_dowhile_go(parser, block, out);
if (label)
mem_d(label);
if (vec_last(parser->loops) != label) {
parseerror(parser, "internal error: label stack corrupted");
rv = false;
ast_delete(*out);
*out = NULL;
}
else
vec_pop(parser->loops);
return rv;
}
static bool parse_dowhile_go(parser_t *parser, ast_block *block, ast_expression **out)
{
ast_loop *aloop;
ast_expression *cond, *ontrue;
@ -2081,11 +2179,6 @@ static bool parse_dowhile(parser_t *parser, ast_block *block, ast_expression **o
(void)block; /* not touching */
/* skip the 'do' and get the body */
if (!parser_next(parser)) {
parseerror(parser, "expected loop body");
return false;
}
if (!parse_statement_or_block(parser, &ontrue))
return false;
@ -2146,7 +2239,57 @@ static bool parse_dowhile(parser_t *parser, ast_block *block, ast_expression **o
return true;
}
static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **out);
static bool parse_for(parser_t *parser, ast_block *block, ast_expression **out)
{
bool rv;
char *label = NULL;
/* skip the 'for' and check for opening paren */
if (!parser_next(parser)) {
if (OPTS_FLAG(LOOP_LABELS))
parseerror(parser, "expected loop label or 'for' expressions in parenthesis");
else
parseerror(parser, "expected 'for' expressions in parenthesis");
return false;
}
if (parser->tok == ':') {
if (!OPTS_FLAG(LOOP_LABELS))
parseerror(parser, "labeled loops not activated, try using -floop-labels");
if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
parseerror(parser, "expected loop label");
return false;
}
label = util_strdup(parser_tokval(parser));
if (!parser_next(parser)) {
mem_d(label);
parseerror(parser, "expected 'for' expressions in parenthesis");
return false;
}
}
if (parser->tok != '(') {
parseerror(parser, "expected 'for' expressions in parenthesis");
return false;
}
vec_push(parser->loops, label);
rv = parse_for_go(parser, block, out);
if (label)
mem_d(label);
if (vec_last(parser->loops) != label) {
parseerror(parser, "internal error: label stack corrupted");
rv = false;
ast_delete(*out);
*out = NULL;
}
else
vec_pop(parser->loops);
return rv;
}
static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **out)
{
ast_loop *aloop;
ast_expression *initexpr, *cond, *increment, *ontrue;
@ -2164,11 +2307,6 @@ static bool parse_for(parser_t *parser, ast_block *block, ast_expression **out)
increment = NULL;
ontrue = NULL;
/* skip the 'while' and check for opening paren */
if (!parser_next(parser) || parser->tok != '(') {
parseerror(parser, "expected 'for' expressions in parenthesis");
goto onerr;
}
/* parse into the expression */
if (!parser_next(parser)) {
parseerror(parser, "expected 'for' initializer after opening paren");
@ -2311,11 +2449,38 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou
static bool parse_break_continue(parser_t *parser, ast_block *block, ast_expression **out, bool is_continue)
{
size_t i;
unsigned int levels = 0;
lex_ctx ctx = parser_ctx(parser);
(void)block; /* not touching */
if (!parser_next(parser)) {
parseerror(parser, "expected semicolon or loop label");
return false;
}
if (!parser_next(parser) || parser->tok != ';') {
if (parser->tok == TOKEN_IDENT) {
if (!OPTS_FLAG(LOOP_LABELS))
parseerror(parser, "labeled loops not activated, try using -floop-labels");
i = vec_size(parser->loops);
while (i--) {
if (parser->loops[i] && !strcmp(parser->loops[i], parser_tokval(parser)))
break;
if (!i) {
parseerror(parser, "no such loop to %s: `%s`",
(is_continue ? "continue" : "break out of"),
parser_tokval(parser));
return false;
}
++levels;
}
if (!parser_next(parser)) {
parseerror(parser, "expected semicolon");
return false;
}
}
if (parser->tok != ';') {
parseerror(parser, "expected semicolon");
return false;
}
@ -2323,7 +2488,7 @@ static bool parse_break_continue(parser_t *parser, ast_block *block, ast_express
if (!parser_next(parser))
parseerror(parser, "parse error");
*out = (ast_expression*)ast_breakcont_new(ctx, is_continue);
*out = (ast_expression*)ast_breakcont_new(ctx, is_continue, levels);
return true;
}