factored out 'if' parsing code into a function, added 'while' parsing, and errors for more unsupported operators

This commit is contained in:
Wolfgang (Blub) Bumiller 2012-08-13 16:45:35 +02:00
parent 5ca3fed36a
commit 1c4a11f6fb

159
parser.c
View file

@ -503,6 +503,7 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy)
out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, exprs[0], exprs[1]);
break;
case opid1('%'):
case opid2('%','='):
parseerror(parser, "qc does not have a modulo operator");
return false;
case opid1('|'):
@ -523,6 +524,8 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy)
case opid2('<','<'):
case opid2('>','>'):
case opid3('<','<','='):
case opid3('>','>','='):
parseerror(parser, "TODO: shifts");
return false;
@ -952,58 +955,8 @@ onerr:
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 bool parser_parse_statement(parser_t *parser, ast_block *block, ast_expression **out)
{
if (parser->tok == TOKEN_TYPENAME)
{
/* local variable */
if (!block) {
parseerror(parser, "cannot declare a variable from here");
return false;
}
if (!parser_variable(parser, block))
return false;
*out = NULL;
return true;
}
else if (parser->tok == TOKEN_KEYWORD)
{
if (!strcmp(parser_tokval(parser), "return"))
{
ast_expression *exp = NULL;
ast_return *ret = NULL;
ast_value *expected = parser->function->vtype;
if (!parser_next(parser)) {
parseerror(parser, "expected return expression");
return false;
}
if (parser->tok != ';') {
exp = parser_expression(parser);
if (!exp)
return false;
if (exp->expression.vtype != expected->expression.next->expression.vtype) {
parseerror(parser, "return with invalid expression");
}
ret = ast_return_new(exp->expression.node.context, exp);
if (!ret) {
ast_delete(exp);
return false;
}
*out = (ast_expression*)ret;
} else if (!parser_next(parser)) {
parseerror(parser, "expected semicolon");
if (expected->expression.next->expression.vtype != TYPE_VOID) {
parseerror(parser, "return without value");
}
}
return true;
}
else if (!strcmp(parser_tokval(parser), "if"))
static bool parser_parse_if(parser_t *parser, ast_block *block, ast_expression **out)
{
ast_ifthen *ifthen;
ast_expression *cond, *ontrue, *onfalse = NULL;
@ -1062,6 +1015,110 @@ static bool parser_parse_statement(parser_t *parser, ast_block *block, ast_expre
*out = (ast_expression*)ifthen;
return true;
}
static bool parser_parse_while(parser_t *parser, ast_block *block, ast_expression **out)
{
ast_loop *aloop;
ast_expression *cond, *ontrue;
lex_ctx ctx = parser_ctx(parser);
/* skip the 'while' and check for opening paren */
if (!parser_next(parser) || parser->tok != '(') {
parseerror(parser, "expected 'if' condition in parenthesis");
return false;
}
/* parse into the expression */
if (!parser_next(parser)) {
parseerror(parser, "expected 'if' condition after opening paren");
return false;
}
/* parse the condition */
cond = parser_expression(parser);
if (!cond)
return false;
/* closing paren */
if (parser->tok != ')') {
parseerror(parser, "expected closing paren after 'if' condition");
ast_delete(cond);
return false;
}
/* parse into the 'then' branch */
if (!parser_next(parser)) {
parseerror(parser, "expected statement for on-true branch of 'if'");
ast_delete(cond);
return false;
}
ontrue = parser_parse_statement_or_block(parser);
if (!ontrue) {
ast_delete(cond);
return false;
}
aloop = ast_loop_new(ctx, NULL, cond, NULL, NULL, ontrue);
*out = (ast_expression*)aloop;
return true;
}
static bool parser_parse_statement(parser_t *parser, ast_block *block, ast_expression **out)
{
if (parser->tok == TOKEN_TYPENAME)
{
/* local variable */
if (!block) {
parseerror(parser, "cannot declare a variable from here");
return false;
}
if (!parser_variable(parser, block))
return false;
*out = NULL;
return true;
}
else if (parser->tok == TOKEN_KEYWORD)
{
if (!strcmp(parser_tokval(parser), "return"))
{
ast_expression *exp = NULL;
ast_return *ret = NULL;
ast_value *expected = parser->function->vtype;
if (!parser_next(parser)) {
parseerror(parser, "expected return expression");
return false;
}
if (parser->tok != ';') {
exp = parser_expression(parser);
if (!exp)
return false;
if (exp->expression.vtype != expected->expression.next->expression.vtype) {
parseerror(parser, "return with invalid expression");
}
ret = ast_return_new(exp->expression.node.context, exp);
if (!ret) {
ast_delete(exp);
return false;
}
*out = (ast_expression*)ret;
} else if (!parser_next(parser)) {
parseerror(parser, "expected semicolon");
if (expected->expression.next->expression.vtype != TYPE_VOID) {
parseerror(parser, "return without value");
}
}
return true;
}
else if (!strcmp(parser_tokval(parser), "if"))
{
return parser_parse_if(parser, block, out);
}
else if (!strcmp(parser_tokval(parser), "while"))
{
return parser_parse_while(parser, block, out);
}
parseerror(parser, "Unexpected keyword");
return false;
}