diff --git a/src/grammar.y b/src/grammar.y index 565cb5a..bf0c954 100644 --- a/src/grammar.y +++ b/src/grammar.y @@ -14,14 +14,23 @@ int yyerror(const char *s); int int_value; struct Expression* expression; struct Statement *statement; + struct StatementList *statement_list; + struct Block *block; + struct Elseif *elseif; } %token BOOL_LITERAL %token DOUBLE_LITERAL %token INT_LITERAL %token IDENTIFIER; +%token FUNCTION IF ELSE FOR RETURN BREAK CONTINUE NIL + +%type expr bool_expr +%type stmt if_stmt +%type stmt_list +%type block +%type elseif elseif_list -%nonassoc '\n' %nonassoc '=' %left AND OR %nonassoc EQ NE @@ -31,18 +40,39 @@ int yyerror(const char *s); %nonassoc MINUS %nonassoc NOT -%type expr -%type stmt - %% + stmt_list: - stmt - | stmt_list stmt + stmt {$$ = allocStatementList($1); } + | stmt_list '\n' stmt {$$ = chainStatementList($1, $3); } ; stmt: - expr '\n' { printExprValue(evalExpression($1)); } + expr { printExprValue(evalExpression($1)); } | IDENTIFIER '=' expr { $$ = allocAssignStatement($1, $3); } + | block { $$ = allocBlockStatement($1); } + | if_stmt + ; + +if_stmt: + IF '(' bool_expr ')' block { $$ = allocIfStatement($3, $5, NULL, NULL); } + | IF '(' bool_expr ')' block ELSE block { $$ = allocIfStatement($3, $5, NULL, $7); } + | IF '(' bool_expr ')' block elseif_list { $$ = allocIfStatement($3, $5, $6, NULL); } + | IF '(' bool_expr ')' block elseif_list ELSE block { $$ = allocIfStatement($3, $5, $6, $8); } + ; + +elseif_list: + elseif + | elseif_list elseif { $$ = chainElseifList($1, $2); } + ; + +elseif: + ELSE IF '(' bool_expr ')' block { $$ = allocElseif($4, $6); } + ; + +block: + '{' stmt_list '}' { $$ = allocBlock($2); } + | '{' '}' { $$ = allocBlock(NULL); } ; expr: @@ -54,18 +84,23 @@ expr: | expr '-' expr { $$ = allocBinaryExpression(SUB_EXPRESSION, $1, $3); } | expr '*' expr { $$ = allocBinaryExpression(MUL_EXPRESSION, $1, $3); } | expr '/' expr { $$ = allocBinaryExpression(DIV_EXPRESSION, $1, $3); } - | expr '>' expr { $$ = allocBinaryExpression(GT_EXPRESSION, $1, $3); } - | expr GE expr { $$ = allocBinaryExpression(GE_EXPRESSION, $1, $3); } - | expr '<' expr { $$ = allocBinaryExpression(LT_EXPRESSION, $1, $3); } - | expr LE expr { $$ = allocBinaryExpression(LE_EXPRESSION, $1, $3); } - | expr EQ expr { $$ = allocBinaryExpression(EQ_EXPRESSION, $1, $3); } - | expr NE expr { $$ = allocBinaryExpression(NE_EXPRESSION, $1, $3); } - | expr AND expr { $$ = allocBinaryExpression(AND_EXPRESSION, $1, $3); } - | expr OR expr { $$ = allocBinaryExpression(OR_EXPRESSION, $1, $3); } - | '!' expr %prec NOT { $$ = allocUnaryExpression(NOT_EXPRESSION, $2); } | '-' expr %prec MINUS { $$ = allocUnaryExpression(MINUS_EXPRESSION, $2); } | '(' expr ')' { $$ = $2; } + | bool_expr ; + +bool_expr: + expr '>' expr { $$ = allocBinaryExpression(GT_EXPRESSION, $1, $3); } + | expr GE expr { $$ = allocBinaryExpression(GE_EXPRESSION, $1, $3); } + | expr '<' expr { $$ = allocBinaryExpression(LT_EXPRESSION, $1, $3); } + | expr LE expr { $$ = allocBinaryExpression(LE_EXPRESSION, $1, $3); } + | expr EQ expr { $$ = allocBinaryExpression(EQ_EXPRESSION, $1, $3); } + | expr NE expr { $$ = allocBinaryExpression(NE_EXPRESSION, $1, $3); } + | expr AND expr { $$ = allocBinaryExpression(AND_EXPRESSION, $1, $3); } + | expr OR expr { $$ = allocBinaryExpression(OR_EXPRESSION, $1, $3); } + | '!' expr %prec NOT { $$ = allocUnaryExpression(NOT_EXPRESSION, $2); } + ; + %% int yyerror(char const *str) { diff --git a/src/lex.l b/src/lex.l index aa2ef1f..0ba66b5 100644 --- a/src/lex.l +++ b/src/lex.l @@ -6,16 +6,24 @@ %% -[+\-*/\(\)<>!\n] { +[+\-*/\(\)<>!{}\n] { return *yytext; } -">=" return GE; -"<=" return LE; -"==" return EQ; -"!=" return NE; -"&&" return AND; -"||" return OR; +">=" return GE; +"<=" return LE; +"==" return EQ; +"!=" return NE; +"&&" return AND; +"||" return OR; +"if" return IF; +"else" return ELSE; +"for" return FOR; +"nil" return NIL; +"func" return FUNCTION; +"return" return RETURN; +"break" return BREAK; +"continue" return CONTINUE; "true"|"false" { yylval.int_value = strcmp(yytext, "false"); diff --git a/src/summoner.c b/src/summoner.c index bdd8f87..27f774f 100644 --- a/src/summoner.c +++ b/src/summoner.c @@ -54,15 +54,88 @@ Expression *allocBinaryExpression(ExpressionKind kind, Expression *left, Express return expr; } -Statement *allocStatement(StatementKind kind) { +Statement *allocStatement(StatementKind kind) +{ Statement *stmt = malloc(sizeof(Statement)); stmt->kind = kind; return stmt; } -Statement *allocAssignStatement(char *variable, Expression *operand) { +Statement *allocAssignStatement(char *variable, Expression *operand) +{ Statement *stmt = allocStatement(ASSIGN_STATEMENT); AssignStatement *assign_s = malloc(sizeof(AssignStatement)); stmt->u.assign_s = assign_s; return stmt; } + +Statement *allocIfStatement(Expression *condition, Block *then_block, Elseif *elseif_list, Block *else_block) +{ + Statement *stmt = allocStatement(IF_STATEMENT); + IfStatement *if_s = malloc(sizeof(IfStatement)); + if_s->condition = condition; + if_s->then_block = then_block; + if_s->elseif_list = elseif_list; + if_s->else_block = else_block; + stmt->u.if_s = if_s; + return stmt; +} + +Statement *allocBlockStatement(Block *block) +{ + Statement *stmt = allocStatement(BLOCK_STATEMENT); + stmt->u.block_s = block; + return stmt; +} + +StatementList *allocStatementList(Statement *statement) +{ + StatementList *stmt_list = malloc(sizeof(StatementList)); + stmt_list->statement = statement; + return stmt_list; +} + +StatementList *chainStatementList(StatementList *list, Statement *statement) +{ + if (list == NULL) + { + return allocStatementList(statement); + } + + StatementList *pos; + for (pos = list; pos->next; pos = pos->next) + ; + + pos->next = allocStatementList(statement); + return list; +} + +Elseif *allocElseif(Expression *condition, Block *block) +{ + Elseif *elseif = malloc(sizeof(Elseif)); + elseif->condition = condition; + elseif->block = block; + return elseif; +} + +Elseif *chainElseifList(Elseif *list, Elseif *elseif) +{ + if (list == NULL) + { + return elseif; + } + + Elseif *pos; + for (pos = list; pos->next; pos = pos->next) + ; + + pos->next = elseif; + return list; +} + +Block *allocBlock(StatementList *list) +{ + Block *block = malloc(sizeof(Block)); + block->statemen_list = list; + return block; +} diff --git a/src/summoner.h b/src/summoner.h index c6d377a..4c60d0e 100644 --- a/src/summoner.h +++ b/src/summoner.h @@ -45,8 +45,6 @@ typedef enum NOT_EXPRESSION, /* ! */ } ExpressionKind; -typedef struct BinaryExpression BinaryExpression; - typedef struct Expression { ExpressionKind kind; @@ -56,7 +54,7 @@ typedef struct Expression int int_value; double double_value; char *identifier; - BinaryExpression *binary_expression; + struct BinaryExpression *binary_expression; struct Expression *unary_expression; } u; @@ -79,6 +77,7 @@ Expression *allocBinaryExpression(ExpressionKind kind, Expression *left, Express typedef enum { ASSIGN_STATEMENT = 1, + BLOCK_STATEMENT, IF_STATEMENT, FOR_STATEMENT, RETURN_STATEMENT, @@ -98,6 +97,8 @@ typedef struct Statement union { AssignStatement *assign_s; + struct Block *block_s; + struct IfStatement *if_s; } u; } Statement; @@ -107,7 +108,34 @@ typedef struct StatementList struct StatementList *next; } StatementList; +typedef struct Block +{ + StatementList *statemen_list; +} Block; + +typedef struct Elseif +{ + Expression *condition; + Block *block; + struct Elseif *next; +} Elseif; + +typedef struct IfStatement +{ + Expression *condition; + Block *then_block; + Elseif *elseif_list; + Block *else_block; +} IfStatement; + Statement *allocStatement(StatementKind kind); Statement *allocAssignStatement(char *variable, Expression *operand); +Statement *allocBlockStatement(Block *block); +Statement *allocIfStatement(Expression *condition, Block *then_block, Elseif *elseif_list, Block *else_block); +StatementList *allocStatementList(Statement *statement); +StatementList *chainStatementList(StatementList *list, Statement *statement); +Elseif *allocElseif(Expression *condition, Block *block); +Elseif *chainElseifList(Elseif *list, Elseif *elseif); +Block *allocBlock(StatementList *list); #endif