From b438dd5ac17c80fbb4494c71c87bba7f3cac0195 Mon Sep 17 00:00:00 2001 From: Mart Lubbers Date: Sun, 7 Feb 2021 19:50:33 +0100 Subject: [PATCH] add field specifiers --- Makefile | 1 - ast.c | 85 +++++++++++++++++++++++++++++++++++++++++--------------- ast.h | 12 ++++++-- expr.c | 2 ++ parse.y | 12 +++++--- scan.l | 3 +- 6 files changed, 83 insertions(+), 32 deletions(-) diff --git a/Makefile b/Makefile index f80df8d..b605a85 100644 --- 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 --- 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; idata.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; idata.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; idata.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; idata.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; idata.an_list.n; i++) diff --git a/ast.h b/ast.h index 1bb93cb..13d3c58 100644 --- 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 --- 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 --- 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 --- 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] ; %% -- 2.20.1