fix pretty printing and make commandline interface
authorMart Lubbers <mart@martlubbers.net>
Tue, 9 Feb 2021 15:06:31 +0000 (16:06 +0100)
committerMart Lubbers <mart@martlubbers.net>
Tue, 9 Feb 2021 15:06:31 +0000 (16:06 +0100)
.gitignore
Makefile
ast.c
ast.h
expr.c [deleted file]
input.txt
parse.y
scan.l
splc.c [new file with mode: 0644]
util.c

index 039961a..d56d33c 100644 (file)
@@ -1,5 +1,5 @@
-expr
-parse.c
-scan.c
+splc
+parse.[ch]
+scan.[ch]
 *.o
-y.tab.h
+y.output
index 7cd4c61..05c5649 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,14 @@
 CFLAGS+=-Wall -Wextra -std=c99 -pedantic -D_XOPEN_SOURCE=700 -ggdb
-YFLAGS+=-Wall -Wno-empty-rule -Wyacc -Wdangling-alias -d --locations
-LFLAGS+=-X
+YFLAGS+=-d --locations -v --defines=parse.h
+LFLAGS+=--header-file=scan.h
 
 OBJECTS:=scan.o parse.o ast.o util.o
 
-all: expr
-expr: $(OBJECTS)
-scan.c: scan.l y.tab.h
-y.tab.h: parse.c
+all: splc
+splc: $(OBJECTS)
+scan.c: scan.l parse.h
+parse.h: parse.c
 expr.c: y.tab.h
 
 clean:
-       $(RM) $(OBJECTS) y.tab.h scan.c parse.c expr
+       $(RM) $(OBJECTS) y.output parse.h scan.h scan.c parse.c expr
diff --git a/ast.c b/ast.c
index 597dfa6..372234e 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -4,7 +4,7 @@
 
 #include "util.h"
 #include "ast.h"
-#include "y.tab.h"
+#include "parse.h"
 
 static const char *binop_str[] = {
        [binor] = "||", [binand] = "&&", [eq] = "==", [neq] = "!=",
@@ -37,7 +37,7 @@ struct vardecl *vardecl(struct type *type, char *ident, struct expr *expr)
 }
 
 struct decl *decl_fun(char *ident, struct list *args, struct list *atypes,
-       struct type *rtype, struct list *vars, struct list *body)
+       struct type *rtype, struct list *body)
 {
        struct decl *res = safe_malloc(sizeof(struct decl));
        res->type = dfundecl;
@@ -47,8 +47,6 @@ struct decl *decl_fun(char *ident, struct list *args, struct list *atypes,
        res->data.dfun.atypes = (struct type **)
                list_to_array(atypes, &res->data.dfun.natypes, true);
        res->data.dfun.rtype = rtype;
-       res->data.dfun.vars = (struct vardecl **)
-               list_to_array(vars, &res->data.dfun.nvar, true);
        res->data.dfun.body = (struct stmt **)
                list_to_array(body, &res->data.dfun.nbody, true);
        return res;
@@ -330,8 +328,6 @@ void decl_print(struct decl *decl, int indent, FILE *out)
                        type_print(decl->data.dfun.rtype, out);
                }
                safe_fprintf(out, " {\n");
-               for (int i = 0; i<decl->data.dfun.nvar; i++)
-                       vardecl_print(decl->data.dfun.vars[i], indent+1, out);
                for (int i = 0; i<decl->data.dfun.nbody; i++)
                        stmt_print(decl->data.dfun.body[i], indent+1, out);
                pindent(indent, out);
@@ -531,9 +527,6 @@ void decl_free(struct decl *decl)
                        type_free(decl->data.dfun.atypes[i]);
                free(decl->data.dfun.atypes);
                type_free(decl->data.dfun.rtype);
-               for (int i = 0; i<decl->data.dfun.nvar; i++)
-                       vardecl_free(decl->data.dfun.vars[i]);
-               free(decl->data.dfun.vars);
                for (int i = 0; i<decl->data.dfun.nbody; i++)
                        stmt_free(decl->data.dfun.body[i]);
                free(decl->data.dfun.body);
diff --git a/ast.h b/ast.h
index 0332e84..f84f08b 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -6,7 +6,7 @@
 
 #include "util.h"
 struct ast;
-#include "y.tab.h"
+#include "parse.h"
 
 struct ast {
        int ndecls;
@@ -43,8 +43,6 @@ struct decl {
                        int natypes;
                        struct type **atypes;
                        struct type *rtype;
-                       int nvar;
-                       struct vardecl **vars;
                        int nbody;
                        struct stmt **body;
                } dfun;
@@ -129,7 +127,7 @@ struct ast *ast(struct list *decls);
 struct vardecl *vardecl(struct type *type, char *ident, struct expr *expr);
 
 struct decl *decl_fun(char *ident, struct list *args, struct list *atypes,
-       struct type *rtype, struct list *vars, struct list *body);
+       struct type *rtype, struct list *body);
 struct decl *decl_var(struct vardecl *vardecl);
 
 struct stmt *stmt_assign(char *ident, struct list *fields, struct expr *expr);
diff --git a/expr.c b/expr.c
deleted file mode 100644 (file)
index 96383c6..0000000
--- a/expr.c
+++ /dev/null
@@ -1,18 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "ast.h"
-#include "y.tab.h"
-extern int yylex_destroy(void);
-
-int main()
-{
-       struct ast *result;
-        int r = yyparse(&result);
-       if (r != 0)
-               return 1;
-       yylex_destroy();
-       ast_print(result, stdout);
-       ast_free(result);
-       return 0;
-}
index 3f8969e..db93041 100644 (file)
--- a/input.txt
+++ b/input.txt
@@ -16,6 +16,12 @@ fun(x){
        "a\br";
        "a\br\"";
        "a\xaar\\\0377\01\xa";
+       Int b = 5;
+       while(true) {
+               Bool b = true;
+               var l = [];
+               5;
+       }
 return 5;
 f(); 
 f(x); f(1, 2, []);
diff --git a/parse.y b/parse.y
index ee3a55a..6229385 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -2,15 +2,15 @@
 #include <stdio.h>
 
 #include "ast.h"
-#include "y.tab.h"
+#include "parse.h"
 
 int yylex(void);
 extern YYLTYPE yylloc;
 
 void yyerror(struct ast **result, const char *str)
 {
-       fprintf(stderr, "%d-%d: %s\n", yylloc.first_line, yylloc.last_column, str);
        (void)result;
+       fprintf(stderr, "%d-%d: %s\n", yylloc.first_line, yylloc.last_column, str);
 }
 
 int yywrap()
@@ -20,6 +20,9 @@ int yywrap()
 
 %}
 
+%define parse.lac full
+%define parse.error verbose
+
 %union {
        struct expr *expr;
        struct stmt *stmt;
@@ -50,7 +53,7 @@ int yywrap()
 %type <ast> start
 %type <decl> fundecl
 %type <expr> expr
-%type <list> args body decls fargs field fnargs nargs funtype vardecls bbody
+%type <list> args body decls fargs field fnargs nargs funtype bbody
 %type <stmt> stmt
 %type <type> type ftype
 %type <vardecl> vardecl
@@ -68,21 +71,17 @@ vardecl
        | type IDENT ASSIGN expr SEMICOLON { $$ = vardecl($1, $2, $4); }
        ;
 fundecl
-       : IDENT BOPEN args BCLOSE CONS CONS funtype ARROW ftype COPEN vardecls body CCLOSE
-               { $$ = decl_fun($1, $3, $7, $9, $11, $12); }
-       | IDENT BOPEN args BCLOSE COPEN vardecls body CCLOSE
-               { $$ = decl_fun($1, $3, NULL, NULL, $6, $7); }
-       ;
-vardecls
-       : /* empty */ { $$ = NULL; }
-       | vardecls vardecl { $$ = list_cons($2, $1); }
+       : IDENT BOPEN args BCLOSE COPEN body CCLOSE
+               { $$ = decl_fun($1, $3, NULL, NULL, $6); }
+       | IDENT BOPEN args BCLOSE CONS CONS funtype ARROW ftype COPEN body CCLOSE
+               { $$ = decl_fun($1, $3, $7, $9, $11); }
        ;
 funtype
        : /* empty */ { $$ = NULL; }
        | funtype ftype { $$ = list_cons($2, $1); }
        ;
 /* don't allow vardecls to be fully polymorph, this complicates parsing a lot */
-type 
+type
        : BOPEN ftype COMMA ftype BCLOSE { $$ = type_tuple($2, $4); }
        | SOPEN ftype SCLOSE { $$ = type_list($2); }
        | TBOOL { $$ = type_basic(btbool); }
@@ -91,12 +90,7 @@ type
        | TVOID { $$ = type_basic(btvoid); }
        ;
 ftype
-       : BOPEN ftype COMMA ftype BCLOSE { $$ = type_tuple($2, $4); }
-       | SOPEN ftype SCLOSE { $$ = type_list($2); }
-       | TBOOL { $$ = type_basic(btbool); }
-       | TCHAR { $$ = type_basic(btchar); }
-       | TINT { $$ = type_basic(btint); }
-       | TVOID { $$ = type_basic(btvoid); }
+       : type
     | IDENT { $$ = type_var($1); }
        ;
 args
diff --git a/scan.l b/scan.l
index 38dab0c..664868c 100644 (file)
--- a/scan.l
+++ b/scan.l
@@ -1,6 +1,6 @@
 D [0-9]
 H [0-9a-fA-F]
-E ([0\\abtnvfr]|x{H}{H}?|0[0-3]{O}{O}|0{O}{O}?)
+E ([0\\abtnvfr]|x{H}?{H}|0[0-3]?{O}?{O})
 I [a-zA-Z_]
 O [0-7]
 
@@ -23,7 +23,7 @@ O [0-7]
     }
 
 #include "ast.h"
-#include "y.tab.h"
+#include "parse.h"
 
 %}
 
diff --git a/splc.c b/splc.c
new file mode 100644 (file)
index 0000000..8d7174c
--- /dev/null
+++ b/splc.c
@@ -0,0 +1,70 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+
+#include "ast.h"
+#include "parse.h"
+#include "scan.h"
+extern int yylex_destroy(void);
+
+void usage(FILE *out, char *arg0)
+{
+       fprintf(out,
+               "Usage: %s [OPTS] [FILE]\n"
+               "\n"
+               "Compile an spl file. If FILE is not specified stdin is used.\n"
+               "\n"
+               "Options:\n"
+               "\t-p\tJust parse and pretty print\n"
+               "\t-t\tJust parse and typecheck\n"
+               "\t-c\tparse, typecheck and compile (default)\n"
+               "\t-h\tShow this help\n"
+               , arg0);
+}
+
+enum mode {parse,type,compile};
+
+int main(int argc, char *argv[])
+{
+       int opt;
+       enum mode mode = compile;
+
+       while ((opt = getopt(argc, argv, "hptc")) != -1) {
+               switch (opt) {
+               case 'p':
+                       mode = parse;
+                       break;
+               case 't':
+                       mode = type;
+                       break;
+               case 'c':
+                       mode = compile;
+                       break;
+               case 'h':
+                       usage(stdout, argv[0]);
+                       return 0;
+               default:
+                       usage(stderr, argv[0]);
+                       return 1;
+               }
+       }
+       if (optind + 1 == argc && strcmp(argv[optind], "-") != 0)
+               if ((yyin = fopen(argv[optind], "r")) == NULL)
+                       pdie("fopen");
+
+       struct ast *result = NULL;
+        int r = yyparse(&result);
+       if (r != 0)
+               return 1;
+       yylex_destroy();
+       if (mode == parse) {
+               ast_print(result, stdout);
+               goto end;
+       }
+end:
+       ast_free(result);
+       if (yyin == stdin)
+               if (fclose(yyin) == -1)
+                       perror("fclose");
+       return 0;
+}
diff --git a/util.c b/util.c
index 09747c9..5103745 100644 (file)
--- a/util.c
+++ b/util.c
@@ -74,6 +74,7 @@ char *escape_char(char c, char *buf, bool str)
        case '\v': strcpy(buf, "\\v"); break;
        case '\f': strcpy(buf, "\\f"); break;
        case '\r': strcpy(buf, "\\r"); break;
+       case '\\': strcpy(buf, "\\\\"); break;
        case '\'': strcpy(buf, str ? "'" : "\\'"); break;
        case '"': strcpy(buf, str ? "\\\"" : "\""); break;
        default: