-expr
-parse.c
-scan.c
+splc
+parse.[ch]
+scan.[ch]
*.o
-y.tab.h
+y.output
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
#include "util.h"
#include "ast.h"
-#include "y.tab.h"
+#include "parse.h"
static const char *binop_str[] = {
[binor] = "||", [binand] = "&&", [eq] = "==", [neq] = "!=",
}
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;
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;
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);
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);
#include "util.h"
struct ast;
-#include "y.tab.h"
+#include "parse.h"
struct ast {
int ndecls;
int natypes;
struct type **atypes;
struct type *rtype;
- int nvar;
- struct vardecl **vars;
int nbody;
struct stmt **body;
} dfun;
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);
+++ /dev/null
-#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;
-}
"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, []);
#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()
%}
+%define parse.lac full
+%define parse.error verbose
+
%union {
struct expr *expr;
struct stmt *stmt;
%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
| 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); }
| 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
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]
}
#include "ast.h"
-#include "y.tab.h"
+#include "parse.h"
%}
--- /dev/null
+#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;
+}
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: