authored by
Yuki Izumi
<yuki@kivikakk.ee>
10 years ago
lang.l
| 5 +++-
lang.y
| 25 +++++++++++++++-----
parser.c
| 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
parser.h
| 12 ++++++++++-
4 files changed, 116 insertions(+), 8 deletions(-)
@@ -1,11 +1,14 @@
%{
+ #include <stdlib.h>
+
#include "parser.h"
#include "lang.tab.h"
%}
%%
-\"[^"\n]+\"? { yylval.expr = ast_string_alloc(yytext + 1); return EXPR; }
+\"[^"\n]+\"? { yylval.expr = ast_string_alloc(yytext + 1); return IMM; }
+[0-9]+ { yylval.expr = ast_integer_alloc(atoi(yytext)); return IMM; }
REM[^\n]+ { yylval.comment = ast_comment_alloc(yytext + 3, 1); return COMMENT; }
'[^\n]+ { yylval.comment = ast_comment_alloc(yytext + 1, 0); return COMMENT; }
[a-zA-Z]+ { yylval.token = ast_token_alloc(yytext); return TOKEN; }
@@ -18,11 +18,16 @@
%token NL
%token <token> TOKEN
-%token <expr> EXPR
+%token <expr> IMM
%token <comment> COMMENT
%type <stmt> line stmt
-%type <expr> exprlist opt_exprlist
+%type <expr> expr exprlist opt_exprlist
+
+%left '+' '-'
+%left '*' '/'
+
+%left '(' ')'
%%
@@ -43,14 +48,22 @@ stmt: TOKEN opt_exprlist { $$ = ast_stmt_alloc(STMT_CALL); $$->ca
| COMMENT { $$ = ast_stmt_alloc(STMT_COMMENT); $$->comment = $1; }
;
-exprlist: EXPR { $$ = $1; }
- | EXPR ',' exprlist { $$ = $1; $1->next = $3; $1->nexttype = ','; }
- | EXPR ';' exprlist { $$ = $1; $1->next = $3; $1->nexttype = ';'; }
- | EXPR exprlist { $$ = $1; $1->next = $2; $1->nexttype = ';'; }
+exprlist: expr { $$ = $1; }
+ | expr ',' exprlist { $$ = $1; $1->next = $3; $1->nexttype = ','; }
+ | expr ';' exprlist { $$ = $1; $1->next = $3; $1->nexttype = ';'; }
+ | expr exprlist { $$ = $1; $1->next = $2; $1->nexttype = ';'; }
;
opt_exprlist: /* empty */ { $$ = 0; }
| exprlist { $$ = $1; }
;
+expr: IMM { $$ = $1; }
+ | '(' expr ')' { $$ = $2; }
+ | expr '+' expr { $$ = ast_binary_alloc('+', $1, $3); }
+ | expr '-' expr { $$ = ast_binary_alloc('-', $1, $3); }
+ | expr '*' expr { $$ = ast_binary_alloc('*', $1, $3); }
+ | expr '/' expr { $$ = ast_binary_alloc('/', $1, $3); }
+;
+
/* vim: set sw=4 et: */
@@ -20,12 +20,44 @@ ast_expr_t *ast_string_alloc(char const *value) {
return expr;
}
+ast_expr_t *ast_binary_alloc(char op, ast_expr_t *a, ast_expr_t *b) {
+ ast_expr_t *expr = malloc(sizeof(*expr));
+ memset(expr, 0, sizeof(*expr));
+ expr->type = EXPR_BINARY;
+ expr->binary.op = op;
+ expr->binary.a = a;
+ expr->binary.b = b;
+
+ return expr;
+}
+
+ast_expr_t *ast_integer_alloc(int i) {
+ ast_expr_t *expr = malloc(sizeof(*expr));
+ memset(expr, 0, sizeof(*expr));
+ expr->type = EXPR_INTEGER;
+ expr->integer = i;
+
+ return expr;
+}
+
void ast_expr_pp(ast_expr_t *expr) {
switch (expr->type) {
case EXPR_STRING:
printf("\"%s\"", expr->string);
break;
+ case EXPR_BINARY:
+ printf("(");
+ ast_expr_pp(expr->binary.a);
+ printf(" %c ", expr->binary.op);
+ ast_expr_pp(expr->binary.b);
+ printf(")");
+ break;
+
+ case EXPR_INTEGER:
+ printf("%d", expr->integer);
+ break;
+
default:
fprintf(stderr, "UNKNOWN EXPR TYPE %d\n", expr->type);
}
@@ -37,12 +69,29 @@ void ast_expr_free(ast_expr_t *expr) {
free(expr->string);
break;
- default:
+ case EXPR_BINARY:
+ ast_expr_free(expr->binary.a);
+ ast_expr_free(expr->binary.b);
break;
+
+ case EXPR_INTEGER:
+ /* empty */
+ break;
+
+ default:
+ fprintf(stderr, "UNKNOWN EXPR TYPE %d\n", expr->type);
}
free(expr);
}
+void ast_expr_free_list(ast_expr_t *expr) {
+ while (expr) {
+ ast_expr_t *next = expr->next;
+ ast_expr_free(expr);
+ expr = next;
+ }
+}
+
/* ast_comment_t */
ast_comment_t *ast_comment_alloc(char const *value, int is_rem) {
@@ -110,9 +159,31 @@ void ast_stmt_pp(ast_stmt_t *stmt) {
}
void ast_stmt_free(ast_stmt_t *stmt) {
+ switch (stmt->type) {
+ case STMT_CALL:
+ ast_token_free(stmt->call.target);
+ ast_expr_free_list(stmt->call.args);
+ break;
+
+ case STMT_COMMENT:
+ ast_comment_free(stmt->comment);
+ break;
+
+ default:
+ fprintf(stderr, "UNKNOWN STMT TYPE %d\n", stmt->type);
+ break;
+ }
free(stmt);
}
+void ast_stmt_free_list(ast_stmt_t *stmt) {
+ while (stmt) {
+ ast_stmt_t *next = stmt->next;
+ ast_stmt_free(stmt);
+ stmt = next;
+ }
+}
+
/* ast_t */
ast_t *ast_alloc(void) {
@@ -138,6 +209,7 @@ void ast_pp(ast_t *ast) {
}
void ast_free(ast_t *ast) {
+ ast_stmt_free_list(ast->stmts);
free(ast);
}
@@ -156,6 +228,14 @@ int parser_test(void) {
begin_scan(
"PRINT \"Hello\"; \"there\", \"pals\" \"!\"\n"
+ "REM 1 + 2 * 3\n"
+ "PRINT 1 + 2 * 3\n"
+ "REM (1 + 2) * 3\n"
+ "PRINT (1 + 2) * 3\n"
+ "REM 1 * 2 + 3\n"
+ "PRINT 1 * 2 + 3\n"
+ "REM 1 * (2 + 3)\n"
+ "PRINT 1 * (2 + 3)\n"
"GOTO\n"
"\n"
"REM Okay, sure thing.\n"
@@ -5,6 +5,8 @@
typedef enum {
EXPR_STRING,
+ EXPR_BINARY,
+ EXPR_INTEGER,
} ast_expr_type_t;
typedef struct ast_expr {
@@ -12,6 +14,12 @@ typedef struct ast_expr {
union {
char *string;
+ struct {
+ char op;
+ struct ast_expr *a;
+ struct ast_expr *b;
+ } binary;
+ int integer;
};
struct ast_expr *next;
@@ -19,8 +27,11 @@ typedef struct ast_expr {
} ast_expr_t;
ast_expr_t *ast_string_alloc(char const *value);
+ast_expr_t *ast_binary_alloc(char op, ast_expr_t *a, ast_expr_t *b);
+ast_expr_t *ast_integer_alloc(int i);
void ast_expr_pp(ast_expr_t *expr);
void ast_expr_free(ast_expr_t *expr);
+void ast_expr_free_list(ast_expr_t *expr);
/* ast_comment_t */
@@ -65,6 +76,7 @@ typedef struct ast_stmt {
ast_stmt_t *ast_stmt_alloc(ast_stmt_type_t type);
void ast_stmt_pp(ast_stmt_t *stmt);
void ast_stmt_free(ast_stmt_t *stmt);
+void ast_stmt_free_list(ast_stmt_t *stmt);
/* ast_t */