--- /dev/null
+expr
+parse.c
+scan.c
+*.o
+y.tab.h
--- /dev/null
+CFLAGS:=-Wall -std=c99 -D_XOPEN_SOURCE=700
+YFLAGS:=-d
+LFLAGS:=-t
+
+OBJECTS:=scan.o parse.o expr.o ast.c
+
+all: expr
+
+scan.c: scan.l y.tab.h
+y.tab.h: parse.c
+
+expr: $(OBJECTS)
+
+clean:
+ $(RM) $(OBJECTS) y.tab.h scan.c parse.c expr
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "ast.h"
+
+struct ast *ast_alloc()
+{
+ struct ast *res = malloc(sizeof(struct ast));
+ if (res == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+ return res;
+}
+
+struct ast *ast_cons(struct ast *el, struct ast *tail)
+{
+ struct ast *res = ast_alloc();
+ res->type = an_cons;
+ res->data.an_cons.el = el;
+ res->data.an_cons.tail = tail;
+ return res;
+}
+
+struct ast *ast_binop(struct ast *l, enum binop op, struct ast *r)
+{
+ struct ast *res = ast_alloc();
+ res->type = an_binop;
+ res->data.an_binop.l = l;
+ res->data.an_binop.op = op;
+ res->data.an_binop.r = r;
+ return res;
+}
+
+struct ast *ast_int(int integer)
+{
+ struct ast *res = ast_alloc();
+ res->type = an_int;
+ res->data.an_int = integer;
+ return res;
+}
+
+static const char *binop_str[] = {
+ [plus] = "+",
+ [minus] = "+",
+ [times] = "+",
+ [divide] = "+",
+};
+
+void ast_print(struct ast * ast, FILE *out)
+{
+ if (ast == NULL)
+ return;
+ switch(ast->type) {
+ case an_binop:
+ fprintf(out, "(");
+ ast_print(ast->data.an_binop.l, out);
+ fprintf(out, "%s", binop_str[ast->data.an_binop.op]);
+ ast_print(ast->data.an_binop.r, out);
+ fprintf(out, ")");
+ break;
+ case an_cons:
+ ast_print(ast->data.an_cons.el, out);
+ fprintf(out, ";\n");
+ ast_print(ast->data.an_cons.tail, out);
+ break;
+ case an_int:
+ fprintf(out, "%d", ast->data.an_int);
+ break;
+ default:
+ fprintf(stderr, "Unsupported AST node\n");
+ exit(1);
+ }
+}
+
+void ast_free(struct ast *ast)
+{
+ if (ast == NULL)
+ return;
+ switch(ast->type) {
+ case an_binop:
+ ast_free(ast->data.an_binop.l);
+ ast_free(ast->data.an_binop.r);
+ break;
+ case an_cons:
+ ast_free(ast->data.an_cons.el);
+ ast_free(ast->data.an_cons.tail);
+ break;
+ case an_int:
+ break;
+ default:
+ fprintf(stderr, "Unsupported AST node\n");
+ exit(1);
+ }
+ free(ast);
+}
--- /dev/null
+#ifndef AST_H
+#define AST_H
+
+#include <stdio.h>
+
+enum binop {plus,minus,times,divide};
+enum ast_type {an_binop, an_cons, an_int};
+struct ast {
+ enum ast_type type;
+ union {
+ struct {
+ struct ast *l;
+ enum binop op;
+ struct ast *r;
+ } an_binop;
+ struct {
+ struct ast *el;
+ struct ast *tail;
+ } an_cons;
+ int an_int;
+
+ } data;
+};
+
+struct ast *ast_cons(struct ast *el, struct ast *tail);
+struct ast *ast_binop(struct ast *l, enum binop op, struct ast *tail);
+struct ast *ast_int(int integer);
+
+void ast_print(struct ast * ast, FILE *out);
+void ast_free(struct ast *ast);
+
+#endif
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include "ast.h"
+
+#include "y.tab.h"
+
+int main()
+{
+ struct ast *result = NULL;
+ int r = yyparse(&result);
+ if (r != 0)
+ return r;
+ ast_print(result, stdout);
+ return 0;
+}
--- /dev/null
+%{
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "ast.h"
+#define YYSTYPE struct ast *
+
+#include "y.tab.h"
+
+int yylex(void);
+
+void yyerror(struct ast **result, const char *str)
+{
+ fprintf(stderr, "error: %s\n", str);
+}
+
+int yywrap()
+{
+ return 1;
+}
+
+%}
+
+%token INTEGER PLUS MINUS TIMES DIVIDE BOPEN BCLOSE SEMICOLON
+%parse-param { struct ast **result }
+
+%%
+
+start : exprs { *result = $1; } ;
+
+exprs
+ : { $$ = NULL; }
+ | exprs expr SEMICOLON { $$ = ast_cons($2, $1); }
+ ;
+
+expr
+ : expr PLUS fact { $$ = ast_binop($1, plus, $3); }
+ | expr MINUS fact { $$ = ast_binop($1, minus, $3); }
+ | fact
+ ;
+
+fact
+ : fact TIMES basic { $$ = ast_binop($1, times, $3); }
+ | fact DIVIDE basic { $$ = ast_binop($1, divide, $3); }
+ | basic
+ ;
+
+basic
+ : INTEGER
+ | BOPEN expr BCLOSE { $$ = $2; }
+ ;
--- /dev/null
+%option noinput
+%option nounput
+%{
+
+#include <stdio.h>
+#include "ast.h"
+#define YYSTYPE struct ast *
+#include "y.tab.h"
+extern YYSTYPE yylval;
+
+%}
+
+%%
+
+[0-9]+ { yylval = ast_int(atoi(yytext)); return INTEGER; }
+\+ return PLUS;
+- return MINUS;
+\* return TIMES;
+\/ return DIVIDE;
+\( return BOPEN;
+\) return BCLOSE;
+\; return SEMICOLON;
+[ \n\t] ;
+
+%%