247 lines
6.8 KiB
C
247 lines
6.8 KiB
C
#include "../parser.h"
|
|
#include "ast.h"
|
|
|
|
ast_node_t* parse_stmt(parser_t* parser) {
|
|
tok_buf_t* tokbuf = &parser->tokbuf;
|
|
flush_peek_tok(tokbuf);
|
|
tok_type_t ttype = peek_tok_type(tokbuf);
|
|
ast_node_t* node = new_ast_node();
|
|
switch (ttype) {
|
|
case TOKEN_IF: {
|
|
/**
|
|
* if (exp) stmt
|
|
* if (exp) stmt else stmt
|
|
*/
|
|
pop_tok(tokbuf);
|
|
|
|
expect_pop_tok(tokbuf, TOKEN_L_PAREN);
|
|
node->if_stmt.cond = parse_expr(parser);
|
|
flush_peek_tok(tokbuf);
|
|
expect_pop_tok(tokbuf, TOKEN_R_PAREN);
|
|
|
|
node->if_stmt.if_stmt = parse_stmt(parser);
|
|
ttype = peek_tok_type(tokbuf);
|
|
if (ttype == TOKEN_ELSE) {
|
|
pop_tok(tokbuf);
|
|
node->if_stmt.else_stmt = parse_stmt(parser);
|
|
} else {
|
|
node->if_stmt.else_stmt = NULL;
|
|
}
|
|
node->type = NT_STMT_IF;
|
|
break;
|
|
}
|
|
case TOKEN_SWITCH: {
|
|
/**
|
|
* switch (exp) stmt
|
|
*/
|
|
pop_tok(tokbuf);
|
|
|
|
expect_pop_tok(tokbuf, TOKEN_L_PAREN);
|
|
node->switch_stmt.cond = parse_expr(parser);
|
|
expect_pop_tok(tokbuf, TOKEN_R_PAREN);
|
|
|
|
node->switch_stmt.body = parse_stmt(parser);
|
|
node->type = NT_STMT_SWITCH;
|
|
break;
|
|
}
|
|
case TOKEN_WHILE: {
|
|
/**
|
|
* while (exp) stmt
|
|
*/
|
|
pop_tok(tokbuf);
|
|
|
|
expect_pop_tok(tokbuf, TOKEN_L_PAREN);
|
|
node->while_stmt.cond = parse_expr(parser);
|
|
expect_pop_tok(tokbuf, TOKEN_R_PAREN);
|
|
|
|
node->while_stmt.body = parse_stmt(parser);
|
|
node->type = NT_STMT_WHILE;
|
|
break;
|
|
}
|
|
case TOKEN_DO: {
|
|
/**
|
|
* do stmt while (exp)
|
|
*/
|
|
pop_tok(tokbuf);
|
|
node->do_while_stmt.body = parse_stmt(parser);
|
|
ttype = peek_tok_type(tokbuf);
|
|
if (ttype != TOKEN_WHILE) {
|
|
error("expected while after do");
|
|
}
|
|
pop_tok(tokbuf);
|
|
expect_pop_tok(tokbuf, TOKEN_L_PAREN);
|
|
node->do_while_stmt.cond = parse_expr(parser);
|
|
expect_pop_tok(tokbuf, TOKEN_R_PAREN);
|
|
node->type = NT_STMT_DOWHILE;
|
|
break;
|
|
}
|
|
case TOKEN_FOR: {
|
|
/**
|
|
* for (init; [cond]; [iter]) stmt
|
|
*/
|
|
// node->children.stmt.for_stmt.init
|
|
pop_tok(tokbuf);
|
|
ttype = peek_tok_type(tokbuf);
|
|
if (ttype != TOKEN_L_PAREN) {
|
|
error("expected ( after for");
|
|
}
|
|
pop_tok(tokbuf);
|
|
|
|
// init expr or init decl_var
|
|
// TODO need add this feature
|
|
if (peek_decl(tokbuf)) {
|
|
node->for_stmt.init = parse_decl_val(parser);
|
|
} else {
|
|
node->for_stmt.init = parse_expr(parser);
|
|
expect_pop_tok(tokbuf, TOKEN_SEMICOLON);
|
|
}
|
|
|
|
// cond expr or null
|
|
ttype = peek_tok_type(tokbuf);
|
|
if (ttype != TOKEN_SEMICOLON) {
|
|
node->for_stmt.cond = parse_expr(parser);
|
|
expect_pop_tok(tokbuf, TOKEN_SEMICOLON);
|
|
} else {
|
|
node->for_stmt.cond = NULL;
|
|
pop_tok(tokbuf);
|
|
}
|
|
|
|
// iter expr or null
|
|
ttype = peek_tok_type(tokbuf);
|
|
if (ttype != TOKEN_R_PAREN) {
|
|
node->for_stmt.iter = parse_expr(parser);
|
|
expect_pop_tok(tokbuf, TOKEN_R_PAREN);
|
|
} else {
|
|
node->for_stmt.iter = NULL;
|
|
pop_tok(tokbuf);
|
|
}
|
|
|
|
node->for_stmt.body = parse_stmt(parser);
|
|
node->type = NT_STMT_FOR;
|
|
break;
|
|
}
|
|
case TOKEN_BREAK: {
|
|
/**
|
|
* break ;
|
|
*/
|
|
// TODO check 导致外围 for、while 或 do-while 循环或 switch 语句终止。
|
|
pop_tok(tokbuf);
|
|
expect_pop_tok(tokbuf, TOKEN_SEMICOLON);
|
|
|
|
node->type = NT_STMT_BREAK;
|
|
break;
|
|
}
|
|
case TOKEN_CONTINUE: {
|
|
/**
|
|
* continue ;
|
|
*/
|
|
// TODO check 导致跳过整个 for、 while 或 do-while 循环体的剩余部分。
|
|
pop_tok(tokbuf);
|
|
expect_pop_tok(tokbuf, TOKEN_SEMICOLON);
|
|
|
|
node->type = NT_STMT_CONTINUE;
|
|
break;
|
|
}
|
|
case TOKEN_RETURN: {
|
|
/**
|
|
* return [exp] ;
|
|
*/
|
|
// TODO 终止当前函数并返回指定值给调用方函数。
|
|
pop_tok(tokbuf);
|
|
ttype = peek_tok_type(tokbuf);
|
|
if (ttype != TOKEN_SEMICOLON) {
|
|
node->return_stmt.expr_stmt = parse_expr(parser);
|
|
flush_peek_tok(tokbuf);
|
|
expect_pop_tok(tokbuf, TOKEN_SEMICOLON);
|
|
} else {
|
|
node->return_stmt.expr_stmt = NULL;
|
|
pop_tok(tokbuf);
|
|
}
|
|
node->type = NT_STMT_RETURN;
|
|
break;
|
|
}
|
|
case TOKEN_GOTO: {
|
|
/**
|
|
* goto label ;
|
|
*/
|
|
// TODO check label 将控制无条件转移到所欲位置。
|
|
//在无法用约定的构造将控制转移到所欲位置时使用。
|
|
pop_tok(tokbuf);
|
|
// find symbol table
|
|
ttype = peek_tok_type(tokbuf);
|
|
if (ttype != TOKEN_IDENT) {
|
|
error("expect identifier after goto");
|
|
}
|
|
expect_pop_tok(tokbuf, TOKEN_SEMICOLON);
|
|
// TODO filling label
|
|
node->goto_stmt.label = expect_pop_ident(tokbuf);
|
|
node->type = NT_STMT_GOTO;
|
|
break;
|
|
}
|
|
case TOKEN_SEMICOLON: {
|
|
/**
|
|
* ;
|
|
* empty stmt using by :
|
|
* while () ;
|
|
* if () ;
|
|
* for () ;
|
|
*/
|
|
pop_tok(tokbuf);
|
|
node->type = NT_STMT_EMPTY;
|
|
break;
|
|
}
|
|
case TOKEN_L_BRACE: {
|
|
/**
|
|
* stmt_block like: { (decl_var | stmt) ... }
|
|
*/
|
|
node->block_stmt.block = parse_block(parser);
|
|
node->type = NT_STMT_BLOCK;
|
|
break;
|
|
}
|
|
case TOKEN_IDENT: {
|
|
// TODO label goto
|
|
if (peek_tok_type(tokbuf) != TOKEN_COLON) {
|
|
goto EXP;
|
|
}
|
|
node->label_stmt.label = expect_pop_ident(tokbuf);
|
|
expect_pop_tok(tokbuf, TOKEN_COLON);
|
|
node->type = NT_STMT_LABEL;
|
|
break;
|
|
}
|
|
case TOKEN_CASE: {
|
|
// TODO label switch
|
|
pop_tok(tokbuf);
|
|
error("unimplemented switch label");
|
|
node->label_stmt.label = parse_expr(parser);
|
|
// TODO 该表达式为const int
|
|
expect_pop_tok(tokbuf, TOKEN_COLON);
|
|
node->type = NT_STMT_CASE;
|
|
break;
|
|
}
|
|
case TOKEN_DEFAULT: {
|
|
// TODO label switch default
|
|
pop_tok(tokbuf);
|
|
expect_pop_tok(tokbuf, TOKEN_COLON);
|
|
node->type = NT_STMT_DEFAULT;
|
|
break;
|
|
}
|
|
default: {
|
|
/**
|
|
* exp ;
|
|
*/
|
|
EXP:
|
|
node->expr_stmt.expr_stmt = parse_expr(parser);
|
|
flush_peek_tok(tokbuf);
|
|
ttype = peek_tok_type(tokbuf);
|
|
if (ttype != TOKEN_SEMICOLON) {
|
|
error("exp must end with \";\"");
|
|
}
|
|
pop_tok(tokbuf);
|
|
node->type = NT_STMT_EXPR;
|
|
break;
|
|
}
|
|
|
|
}
|
|
return node;
|
|
}
|