use builtin operator associativity functionality
authorMart Lubbers <mart@martlubbers.net>
Fri, 5 Feb 2021 12:27:01 +0000 (13:27 +0100)
committerMart Lubbers <mart@martlubbers.net>
Fri, 5 Feb 2021 12:27:01 +0000 (13:27 +0100)
ast.c
ast.h
parse.y
scan.l

diff --git a/ast.c b/ast.c
index b220f5e..4d89925 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -40,11 +40,34 @@ struct ast *ast_int(int integer)
        return res;
 }
 
+struct ast *ast_unop(enum unop op, struct ast *l)
+{
+       struct ast *res = ast_alloc();
+       res->type = an_unop;
+       res->data.an_unop.op = op;
+       res->data.an_unop.l = l;
+       return res;
+}
 static const char *binop_str[] = {
+       [binor] = "||",
+       [binand] = "&&",
+       [eq] = "==",
+       [neq] = "!=",
+       [leq] = "<=",
+       [le] = "<",
+       [geq] = ">=",
+       [ge] = ">",
+       [cons] = ":",
        [plus] = "+",
-       [minus] = "+",
-       [times] = "+",
-       [divide] = "+",
+       [minus] = "-",
+       [times] = "*",
+       [divide] = "/",
+       [modulo] = "%",
+       [power] = "^",
+};
+static const char *unop_str[] = {
+       [inverse] = "!",
+       [negate] = "-",
 };
 
 void ast_print(struct ast * ast, FILE *out)
@@ -67,6 +90,11 @@ void ast_print(struct ast * ast, FILE *out)
        case an_int:
                fprintf(out, "%d", ast->data.an_int);
                break;
+       case an_unop:
+               fprintf(out, "(-");
+               ast_print(ast->data.an_unop.l, out);
+               fprintf(out, ")");
+               break;
        default:
                fprintf(stderr, "Unsupported AST node\n");
                exit(1);
diff --git a/ast.h b/ast.h
index 758d034..872e25c 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -3,8 +3,13 @@
 
 #include <stdio.h>
 
-enum binop {plus,minus,times,divide};
-enum ast_type {an_binop, an_cons, an_int};
+enum binop {
+       binor,binand,
+       eq,neq,leq,le,geq,ge,
+       cons,plus,minus,times,divide,modulo,power
+};
+enum unop {negate,inverse};
+enum ast_type {an_binop, an_cons, an_int, an_unop};
 struct ast {
        enum ast_type type;
        union {
@@ -18,6 +23,10 @@ struct ast {
                        struct ast *tail;
                } an_cons;
                int an_int;
+               struct {
+                       enum unop op;
+                       struct ast *l;
+               } an_unop;
 
        } data;
 };
@@ -25,6 +34,7 @@ struct ast {
 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);
+struct ast *ast_unop(enum unop op, struct ast *l);
 
 void ast_print(struct ast * ast, FILE *out);
 void ast_free(struct ast *ast);
diff --git a/parse.y b/parse.y
index 60d4e0d..6600e5b 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -8,6 +8,7 @@
 
 #include "y.tab.h"
 
+int yylex_debug = 1;
 int yylex(void);
 
 void yyerror(struct ast **result, const char *str)
@@ -22,9 +23,19 @@ int yywrap()
 
 %}
 
-%token INTEGER PLUS MINUS TIMES DIVIDE BOPEN BCLOSE SEMICOLON
+%define parse.error verbose
+%token INTEGER PLUS MINUS TIMES DIVIDE BOPEN BCLOSE SEMICOLON POWER CONS MODULO BINOR BINAND INVERSE
+
 %parse-param { struct ast **result }
 
+%right BINOR
+%right BINAND
+%nonassoc EQ NEQ LEQ LE GEQ GE
+%right CONS
+%left PLUS MINUS
+%left TIMES DIVIDE MODULO
+%right POWER
+
 %%
 
 start : exprs { *result = $1; } ;
@@ -35,18 +46,23 @@ exprs
        ;
 
 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
+       : expr BINOR expr { $$ = ast_binop($1, binor, $3); }
+       | expr BINAND expr { $$ = ast_binop($1, binand, $3); }
+       | expr EQ expr { $$ = ast_binop($1, eq, $3); }
+       | expr NEQ expr { $$ = ast_binop($1, neq, $3); }
+       | expr LEQ expr { $$ = ast_binop($1, leq, $3); }
+       | expr LE expr { $$ = ast_binop($1, le, $3); }
+       | expr GEQ expr { $$ = ast_binop($1, geq, $3); }
+       | expr GE expr { $$ = ast_binop($1, ge, $3); }
+       | expr CONS expr { $$ = ast_binop($1, cons, $3); }
+       | expr PLUS expr { $$ = ast_binop($1, plus, $3); }
+       | expr MINUS expr { $$ = ast_binop($1, minus, $3); }
+       | expr TIMES expr { $$ = ast_binop($1, times, $3); }
+       | expr DIVIDE expr { $$ = ast_binop($1, divide, $3); }
+       | expr MODULO expr { $$ = ast_binop($1, modulo, $3); }
+       | expr POWER expr { $$ = ast_binop($1, power, $3); }
+       | MINUS expr { $$ = ast_unop(negate, $2); }
+       | INVERSE expr { $$ = ast_unop(inverse, $2); }
        | BOPEN expr BCLOSE { $$ = $2; }
+       | INTEGER
        ;
diff --git a/scan.l b/scan.l
index bb34a5b..f92af61 100644 (file)
--- a/scan.l
+++ b/scan.l
@@ -13,10 +13,22 @@ extern YYSTYPE yylval;
 %%
 
 [0-9]+      { yylval = ast_int(atoi(yytext)); return INTEGER; }
+!           return INVERSE;
+\|\|        return BINOR;
+&&          return BINAND;
+==          return EQ;
+!=          return NEQ;
+\<=         return GEQ;
+\<          return GE;
+>=          return LEQ;
+>           return LE;
+:           return CONS;
 \+          return PLUS;
 -           return MINUS;
 \*          return TIMES;
 \/          return DIVIDE;
+%           return MODULO;
+\^          return POWER;
 \(          return BOPEN;
 \)          return BCLOSE;
 \;          return SEMICOLON;