add field specifiers
authorMart Lubbers <mart@martlubbers.net>
Sun, 7 Feb 2021 18:50:33 +0000 (19:50 +0100)
committerMart Lubbers <mart@martlubbers.net>
Sun, 7 Feb 2021 18:50:33 +0000 (19:50 +0100)
Makefile
ast.c
ast.h
expr.c
parse.y
scan.l

index f80df8d..b605a85 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,5 @@
 CFLAGS:=-Wall -Wextra -Werror -std=c99 -pedantic-errors -D_XOPEN_SOURCE=700 -ggdb
 YFLAGS:=-d
-LFLAGS:=-t
 
 OBJECTS:=scan.o parse.o ast.o util.o
 
diff --git a/ast.c b/ast.c
index 23619ec..97bd1ad 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -10,9 +10,9 @@ static const char *ast_type_str[] = {
        [an_assign] = "assign", [an_bool] = "bool", [an_binop] = "binop",
        [an_char] = "char", [an_cons] = "cons", [an_funcall] = "funcall",
        [an_fundecl] = "fundecl", [an_ident] = "ident", [an_if] = "if",
-       [an_int] = "int", [an_list] = "list", [an_return] = "return",
-       [an_stmt_expr] = "stmt_expr", [an_unop] = "unop",
-       [an_vardecl] = "vardecl", [an_while] = "while",
+       [an_int] = "int", [an_nil] = "nil", [an_list] = "list",
+       [an_return] = "return", [an_stmt_expr] = "stmt_expr",
+       [an_unop] = "unop", [an_vardecl] = "vardecl", [an_while] = "while",
 };
 #endif
 static const char *binop_str[] = {
@@ -21,6 +21,8 @@ static const char *binop_str[] = {
        [plus] = "+", [minus] = "-", [times] = "*", [divide] = "/",
        [modulo] = "%", [power] = "^",
 };
+static const char *fieldspec_str[] = {
+       [fst] = "fst", [snd] = "snd", [hd] = "hd", [tl] = "tl"};
 static const char *unop_str[] = { [inverse] = "!", [negate] = "-", };
 
 #ifdef DEBUG
@@ -41,11 +43,7 @@ struct ast *ast_assign(struct ast *ident, struct ast *expr)
 {
        struct ast *res = ast_alloc();
        res->type = an_assign;
-
-       must_be(ident, an_ident, "ident of an assign");
-       res->data.an_assign.ident = ident->data.an_ident;
-       free(ident);
-
+       res->data.an_assign.ident = ident;
        res->data.an_assign.expr = expr;
        return res;
 }
@@ -119,7 +117,8 @@ struct ast *ast_funcall(struct ast *ident, struct ast *args)
 
        //ident
        must_be(ident, an_ident, "ident of a funcall");
-       res->data.an_funcall.ident = ident->data.an_ident;
+       res->data.an_funcall.ident = ident->data.an_ident.ident;
+       free(ident->data.an_ident.fields);
        free(ident);
 
        //args
@@ -137,18 +136,19 @@ struct ast *ast_fundecl(struct ast *ident, struct ast *args, struct ast *body)
 
        //ident
        must_be(ident, an_ident, "ident of a fundecl");
-       res->data.an_fundecl.ident = ident->data.an_ident;
+       res->data.an_fundecl.ident = ident->data.an_ident.ident;
+       free(ident->data.an_ident.fields);
        free(ident);
 
        //args
        must_be(args, an_list, "args of a fundecl");
        res->data.an_fundecl.nargs = args->data.an_list.n;
-       res->data.an_fundecl.args = (char **)safe_malloc(
-               args->data.an_list.n*sizeof(char *));
+       res->data.an_fundecl.args = (char **)args->data.an_list.ptr;
        for (int i = 0; i<args->data.an_list.n; i++) {
                struct ast *e = args->data.an_list.ptr[i];
                must_be(e, an_ident, "arg of a fundecl")
-               res->data.an_fundecl.args[i] = e->data.an_ident;
+               res->data.an_fundecl.args[i] = e->data.an_ident.ident;
+               free(e->data.an_ident.fields);
                free(e);
        }
        free(args);
@@ -168,12 +168,12 @@ struct ast *ast_if(struct ast *pred, struct ast *then, struct ast *els)
        res->type = an_if;
        res->data.an_if.pred = pred;
 
-       must_be(body, an_list, "body of a then");
+       must_be(then, an_list, "body of a then");
        res->data.an_if.nthen = then->data.an_list.n;
        res->data.an_if.then = then->data.an_list.ptr;
        free(then);
 
-       must_be(body, an_list, "body of a els");
+       must_be(els, an_list, "body of a els");
        res->data.an_if.nels = els->data.an_list.n;
        res->data.an_if.els = els->data.an_list.ptr;
        free(els);
@@ -189,11 +189,44 @@ struct ast *ast_int(int integer)
        return res;
 }
 
-struct ast *ast_ident(char *ident)
+struct ast *ast_identc(char *ident)
+{
+       struct ast *res = ast_alloc();
+       res->type = an_ident;
+       res->data.an_ident.ident = safe_strdup(ident);
+       res->data.an_ident.nfields = 0;
+       res->data.an_ident.fields = NULL;
+       return res;
+}
+
+struct ast *ast_ident(struct ast *ident, struct ast *fields)
 {
        struct ast *res = ast_alloc();
        res->type = an_ident;
-       res->data.an_ident = safe_strdup(ident);
+       must_be(fields, an_ident, "ident of an ident");
+       res->data.an_ident.ident = ident->data.an_ident.ident;
+       free(ident);
+
+       must_be(fields, an_list, "fields of an ident");
+       res->data.an_ident.nfields = fields->data.an_list.n;
+       res->data.an_ident.fields = (enum fieldspec *)safe_malloc(
+               fields->data.an_list.n*sizeof(enum fieldspec));
+       for (int i = 0; i<fields->data.an_list.n; i++) {
+               struct ast *t = fields->data.an_list.ptr[i];
+               must_be(t, an_ident, "field of an ident");
+               if (strcmp(t->data.an_ident.ident, "fst") == 0)
+                       res->data.an_ident.fields[i] = fst;
+               else if (strcmp(t->data.an_ident.ident, "snd") == 0)
+                       res->data.an_ident.fields[i] = snd;
+               else if (strcmp(t->data.an_ident.ident, "hd") == 0)
+                       res->data.an_ident.fields[i] = hd;
+               else if (strcmp(t->data.an_ident.ident, "tl") == 0)
+                       res->data.an_ident.fields[i] = tl;
+               free(t->data.an_ident.ident);
+               free(t);
+       }
+       free(fields->data.an_list.ptr);
+       free(fields);
        return res;
 }
 
@@ -258,7 +291,8 @@ struct ast *ast_vardecl(struct ast *ident, struct ast *l)
        res->type = an_vardecl;
        must_be(ident, an_ident, "ident of a vardecl");
 
-       res->data.an_vardecl.ident = ident->data.an_ident;
+       res->data.an_vardecl.ident = ident->data.an_ident.ident;
+       free(ident->data.an_ident.fields);
        free(ident);
        res->data.an_vardecl.l = l;
        return res;
@@ -311,7 +345,8 @@ void ast_print(struct ast *ast, int indent, FILE *out)
        switch(ast->type) {
        case an_assign:
                pindent(indent, out);
-               safe_fprintf(out, "%s = ", ast->data.an_assign.ident);
+               ast_print(ast->data.an_assign.ident, indent, out);
+               safe_fprintf(out, " = ");
                ast_print(ast->data.an_assign.expr, indent, out);
                safe_fprintf(out, ";\n");
                break;
@@ -375,7 +410,10 @@ void ast_print(struct ast *ast, int indent, FILE *out)
                safe_fprintf(out, "%d", ast->data.an_int);
                break;
        case an_ident:
-               safe_fprintf(out, "%s", ast->data.an_ident);
+               fprintf(out, "%s", ast->data.an_ident.ident);
+               for (int i = 0; i<ast->data.an_ident.nfields; i++)
+                       fprintf(out, ".%s",
+                               fieldspec_str[ast->data.an_ident.fields[i]]);
                break;
        case an_cons:
                ast_print(ast->data.an_cons.el, indent, out);
@@ -435,7 +473,7 @@ void ast_free(struct ast *ast)
 #endif
        switch(ast->type) {
        case an_assign:
-               free(ast->data.an_assign.ident);
+               ast_free(ast->data.an_assign.ident);
                ast_free(ast->data.an_assign.expr);
                break;
        case an_binop:
@@ -453,7 +491,7 @@ void ast_free(struct ast *ast)
        case an_funcall:
                free(ast->data.an_funcall.ident);
                for (int i = 0; i<ast->data.an_fundecl.nargs; i++)
-                       free(ast->data.an_fundecl.args[i]);
+                       ast_free(ast->data.an_funcall.args[i]);
                free(ast->data.an_funcall.args);
                break;
        case an_fundecl:
@@ -477,7 +515,8 @@ void ast_free(struct ast *ast)
        case an_int:
                break;
        case an_ident:
-               free(ast->data.an_ident);
+               free(ast->data.an_ident.ident);
+               free(ast->data.an_ident.fields);
                break;
        case an_list:
                for (int i = 0; i<ast->data.an_list.n; i++)
diff --git a/ast.h b/ast.h
index 1bb93cb..13d3c58 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -9,6 +9,7 @@ enum binop {
        eq,neq,leq,le,geq,ge,
        cons,plus,minus,times,divide,modulo,power
 };
+enum fieldspec {fst,snd,hd,tl};
 enum unop {negate,inverse};
 enum ast_type {
        an_assign, an_binop, an_bool, an_char, an_cons, an_funcall, an_fundecl,
@@ -19,7 +20,7 @@ struct ast {
        enum ast_type type;
        union {
                struct {
-                       char *ident;
+                       struct ast *ident;
                        struct ast *expr;
                } an_assign;
                bool an_bool;
@@ -53,7 +54,11 @@ struct ast {
                        struct ast **els;
                } an_if;
                int an_int;
-               char *an_ident;
+               struct {
+                       char *ident;
+                       int nfields;
+                       enum fieldspec *fields;
+               } an_ident;
                struct {
                        int n;
                        struct ast **ptr;
@@ -86,7 +91,8 @@ struct ast *ast_funcall(struct ast *ident, struct ast *args);
 struct ast *ast_fundecl(struct ast *ident, struct ast *args, struct ast *body);
 struct ast *ast_if(struct ast *pred, struct ast *then, struct ast *els);
 struct ast *ast_int(int integer);
-struct ast *ast_ident(char *ident);
+struct ast *ast_identc(char *ident);
+struct ast *ast_ident(struct ast *ident, struct ast *fields);
 struct ast *ast_list(struct ast *llist);
 struct ast *ast_nil();
 struct ast *ast_return(struct ast *rtrn);
diff --git a/expr.c b/expr.c
index 9cde378..b5c8228 100644 (file)
--- a/expr.c
+++ b/expr.c
@@ -3,6 +3,7 @@
 #include "ast.h"
 
 #include "y.tab.h"
+extern int yylex_destroy(void);
 
 int main()
 {
@@ -10,6 +11,7 @@ int main()
         int r = yyparse(&result);
        if (r != 0)
                return r;
+       yylex_destroy();
        ast_print(result, 0, stdout);
        ast_free(result);
        return 0;
diff --git a/parse.y b/parse.y
index 9c24ef0..c79a1ec 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -26,8 +26,8 @@ int yywrap()
 
 //%define parse.error verbose
 %token ASSIGN BCLOSE BINAND BINOR BOOL BOPEN CCLOSE CHAR COMMA CONS COPEN
-%token DIVIDE ELSE IDENT IF INTEGER INVERSE MINUS MODULO NIL PLUS POWER RETURN
-%token SEMICOLON TIMES VAR WHILE
+%token DIVIDE DOT ELSE IDENT IF INTEGER INVERSE MINUS MODULO NIL PLUS POWER
+%token RETURN SEMICOLON TIMES VAR WHILE
 
 %parse-param { struct ast **result }
 
@@ -92,6 +92,10 @@ stmt
        | RETURN SEMICOLON { $$ = ast_return(NULL); }
        ;
 
+field
+       : { $$ = NULL; }
+       | field DOT IDENT { $$ = ast_cons($3, $1); }
+
 expr
        : expr BINOR expr { $$ = ast_binop($1, binor, $3); }
        | expr BINAND expr { $$ = ast_binop($1, binand, $3); }
@@ -109,12 +113,12 @@ expr
        | 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); }
+       | INVERSE expr %prec TIMES { $$ = ast_unop(inverse, $2); }
        | BOPEN expr BCLOSE { $$ = $2; }
        | IDENT BOPEN fargs BCLOSE { $$ = ast_funcall($1, ast_list($3)); }
        | INTEGER
        | BOOL
        | CHAR
-       | IDENT
+       | IDENT field { $$ = ast_ident($1, ast_list($2)); }
        | NIL { $$ = ast_nil(); }
        ;
diff --git a/scan.l b/scan.l
index 3a2eabc..c6ebb87 100644 (file)
--- a/scan.l
+++ b/scan.l
@@ -42,13 +42,14 @@ return      return RETURN;
 \}          return CCLOSE;
 \;          return SEMICOLON;
 \[\]        return NIL;
+\.          return DOT;
 ,           return COMMA;
 '([^']|\\[abtnvfr]|\\x[0-9a-fA-F]{2})' {
        yylval = ast_char(yytext); return CHAR; }
 [0-9]+ {
        yylval = ast_int(atoi(yytext)); return INTEGER; }
 [_a-zA-Z][_a-zA-Z0-9]* {
-       yylval = ast_ident(yytext); return IDENT; }
+       yylval = ast_identc(yytext); return IDENT; }
 [ \n\t]  ;
 
 %%