diff options
author | Ori Bernstein <ori@odin.theasylum> | 2011-11-05 01:32:46 -0400 |
---|---|---|
committer | Ori Bernstein <ori@odin.theasylum> | 2011-11-05 01:34:58 -0400 |
commit | a23fd593dadd3806339a7bbadc89031a8f542cf5 (patch) | |
tree | cd51bfe84f24f8aba6fd4aaf0885cb03b0e13f73 | |
download | mc-a23fd593dadd3806339a7bbadc89031a8f542cf5.tar.gz |
Initial commit
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | mk/c.mk | 73 | ||||
-rw-r--r-- | mk/lexyacc.mk | 9 | ||||
-rw-r--r-- | parse/Makefile | 18 | ||||
-rw-r--r-- | parse/dump.c | 84 | ||||
-rw-r--r-- | parse/gram.y | 475 | ||||
-rw-r--r-- | parse/lits.def | 7 | ||||
-rw-r--r-- | parse/main.c | 55 | ||||
-rw-r--r-- | parse/names.c | 56 | ||||
-rw-r--r-- | parse/node.c | 181 | ||||
-rw-r--r-- | parse/nodes.def | 9 | ||||
-rw-r--r-- | parse/ops.def | 51 | ||||
-rw-r--r-- | parse/parse.h | 210 | ||||
-rw-r--r-- | parse/tok.c | 488 | ||||
-rw-r--r-- | parse/type.c | 157 | ||||
-rw-r--r-- | parse/types.def | 41 | ||||
-rw-r--r-- | parse/util.c | 66 |
17 files changed, 1987 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0779d93 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +SUB = parse + +-include config.mk +include mk/c.mk + +check: + make -C test check @@ -0,0 +1,73 @@ +DEPSDIR = .deps +DEPS=$(addprefix $(DEPSDIR)/, $(OBJ:.o=.d)) + +CFLAGS += -Wall -Werror +CFLAGS += -g +CFLAGS += -MMD -MP -MF ${DEPSDIR}/$(subst /,-,$*).d + +.PHONY: clean clean-gen clean-bin clean-obj clean-misc clean-backups +.PHONY: all + +all: subdirs $(BIN) $(LIB) $(EXTRA) +install: subdirs-install install-bin install-lib install-hdr install-pc + +$(LIB): $(OBJ) + $(AR) -rcs $@ $^ + +$(BIN): $(OBJ) $(EXTRADEP) + $(CC) -o $@ $(OBJ) $(LDFLAGS) + +subdirs: + @for i in $(SUB); do (\ + cd $$i && \ + $(MAKE) || \ + exit 1 \ + ) || exit 1; done + +subdirs-clean: + @for i in $(SUB); do (\ + cd $$i && \ + $(MAKE) clean|| \ + exit 1 \ + ); done + +subdirs-install: + @for i in $(SUB); do (\ + cd $$i && \ + $(MAKE) install|| \ + exit 1 \ + ); done + + +clean: subdirs-clean + rm -f ${BIN} ${OBJ} ${CLEAN} + + +install-bin: $(INSTBIN) + mkdir -p $(INST_ROOT)/bin + test -z "$(INSTBIN)" || install $(INSTBIN) $(INST_ROOT)/bin + +install-lib: $(INSTLIB) + mkdir -p $(INST_ROOT)/lib + test -z "$(INSTLIB)" || install $(INSTLIB) $(INST_ROOT)/lib + +install-hdr: $(INSTHDR) + mkdir -p $(INST_ROOT)/$(HDRDIR)/include + test -z "$(INSTHDR)" || install $(INSTHDR) $(INST_ROOT)/include + +install-pc: $(INSTPKG) + mkdir -p $(INST_ROOT)/pkgconfig + test -z "$(INSTPC)" || install $(INSTPC) $(INST_ROOT)/pkgconfig + +clean-backups: + find ./ -name .*.sw* -exec rm -f {} \; + find ./ -name *.bak -exec rm -f {} \; + +%.o: %.c .deps + $(CC) -c $(CFLAGS) $< + +.deps: + mkdir -p $(DEPSDIR) + + +-include $(DEPS) diff --git a/mk/lexyacc.mk b/mk/lexyacc.mk new file mode 100644 index 0000000..8d104f6 --- /dev/null +++ b/mk/lexyacc.mk @@ -0,0 +1,9 @@ +NECFLAGS = $(subst -Werror,,$(subst -Wall,,$(CFLAGS))) + +%.o: %.y .deps + yacc -d -o$*.c $< + $(CC) -c $(NECFLAGS) $*.c + +%.o: %.l .deps + flex -o$*.c $< + $(CC) -c $(NECFLAGS) $*.c diff --git a/parse/Makefile b/parse/Makefile new file mode 100644 index 0000000..9693c1b --- /dev/null +++ b/parse/Makefile @@ -0,0 +1,18 @@ +BIN=pt +OBJ=dump.o \ + main.o \ + names.o \ + node.o \ + gram.o \ + tok.o \ + type.o \ + util.o + +CLEAN=gram.c + +include ../mk/lexyacc.mk +include ../mk/c.mk + +ops.o: ../mc/ops.c + $(CC) -c $(CFLAGS) $< + diff --git a/parse/dump.c b/parse/dump.c new file mode 100644 index 0000000..af483c6 --- /dev/null +++ b/parse/dump.c @@ -0,0 +1,84 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <ctype.h> +#include <string.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "parse.h" + +static void indent(FILE *fd, int depth) +{ + int i; + for (i = 0; i < 4*depth; i++) + fprintf(fd, " "); +} + +static void dumpnode(Node *n, FILE *fd, int depth) +{ + int i; + + + indent(fd, depth); + fprintf(fd, "%s", nodestr(n->type)); + switch(n->type) { + case Nfile: + fprintf(fd, "(name = %s)\n", n->file.name); + break; + case Nblock: + for (i = 0; i < n->block.nstmts; i++) + dumpnode(n->block.stmts[i], fd, depth+1); + break; + case Nifstmt: + dumpnode(n->ifstmt.cond, fd, depth+1); + dumpnode(n->ifstmt.iftrue, fd, depth+1); + dumpnode(n->ifstmt.iffalse, fd, depth+1); + break; + case Nloopstmt: + dumpnode(n->loopstmt.init, fd, depth+1); + dumpnode(n->loopstmt.cond, fd, depth+1); + dumpnode(n->loopstmt.incr, fd, depth+1); + dumpnode(n->loopstmt.body, fd, depth+1); + break; + case Nuse: + fprintf(fd, " (name = %s, islocal = %d)\n", n->use.name, n->use.islocal); + break; + case Nexpr: + fprintf(fd, " (op = %s, isconst = %d)\n", opstr(n->expr.op), n->expr.isconst); + for (i = 0; i < n->expr.nargs; i++) + dumpnode(n->expr.args[i], fd, depth+1); + break; + case Nlit: + indent(fd, depth); + switch (n->lit.littype) { + case Lchr: fprintf(fd, "Lchr %c\n", n->lit.chrval); break; + case Lbool: fprintf(fd, "Lbool %s\n", n->lit.boolval ? "true" : "false"); break; + case Lint: fprintf(fd, "Lint %ld\n", n->lit.intval); break; + case Lflt: fprintf(fd, "Lflt %lf\n", n->lit.fltval); break; + /* + case Lfunc: fprintf("Lfunc %s\n", n->lit.chrval); break; + case Larray: fprintf("Larray %c\n", n->lit.chrval); break; + */ + default: die("Bad literal type"); break; + } + break; + case Nname: + fprintf(fd, "("); + for (i = 0; i < n->name.nparts; i++) { + if (i != 0) + fprintf(fd, "."); + fprintf(fd, "%s", n->name.parts[i]); + } + fprintf(fd, ")\n"); + break; + } +} + +void dump(Node *n, FILE *fd) +{ + dumpnode(n, fd, 0); +} diff --git a/parse/gram.y b/parse/gram.y new file mode 100644 index 0000000..183939f --- /dev/null +++ b/parse/gram.y @@ -0,0 +1,475 @@ +%{ +#define YYERROR_VERBOSE + +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <ctype.h> +#include <string.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "parse.h" + +void yyerror(const char *s); +int yylex(void); +Op binop(int toktype); +Stab *curscope; +%} + +%token<tok> TError +%token<tok> TPlus /* + */ +%token<tok> TMinus /* - */ +%token<tok> TStar /* * */ +%token<tok> TDiv /* / */ +%token<tok> TInc /* ++ */ +%token<tok> TDec /* -- */ +%token<tok> TMod /* % */ +%token<tok> TAsn /* = */ +%token<tok> TAddeq /* += */ +%token<tok> TSubeq /* -= */ +%token<tok> TMuleq /* *= */ +%token<tok> TDiveq /* /= */ +%token<tok> TModeq /* %= */ +%token<tok> TBoreq /* |= */ +%token<tok> TBxoreq /* ^= */ +%token<tok> TBandeq /* &= */ +%token<tok> TBsleq /* <<= */ +%token<tok> TBsreq /* >>= */ + +%token<tok> TBor /* | */ +%token<tok> TBxor /* ^ */ +%token<tok> TBand /* & */ +%token<tok> TBsl /* << */ +%token<tok> TBsr /* >> */ +%token<tok> TBnot /* ~ */ + +%token<tok> TEq /* == */ +%token<tok> TGt /* > */ +%token<tok> TLt /* < */ +%token<tok> TGe /* >= */ +%token<tok> TLe /* <= */ +%token<tok> TNe /* != */ + +%token<tok> TLor /* || */ +%token<tok> TLand /* && */ +%token<tok> TLnot /* ! */ + +%token<tok> TObrace /* { */ +%token<tok> TCbrace /* } */ +%token<tok> TOparen /* ( */ +%token<tok> TCparen /* ) */ +%token<tok> TOsqbrac /* [ */ +%token<tok> TCsqbrac /* ] */ +%token<tok> TAt /* @ */ + +%token<tok> TType /* type */ +%token<tok> TFor /* for */ +%token<tok> TWhile /* while */ +%token<tok> TIf /* if */ +%token<tok> TElse /* else */ +%token<tok> TElif /* else */ +%token<tok> TMatch /* match */ +%token<tok> TDefault /* default */ +%token<tok> TGoto /* goto */ + +%token<tok><tok> TIntlit +%token<tok><tok> TStrlit +%token<tok><tok> TFloatlit +%token<tok><tok> TChrlit +%token<tok><tok> TBoollit + +%token<tok> TEnum /* enum */ +%token<tok> TStruct /* struct */ +%token<tok> TUnion /* union */ + +%token<tok> TConst /* const */ +%token<tok> TVar /* var */ +%token<tok> TExtern /* extern */ + +%token<tok> TExport /* export */ +%token<tok> TProtect /* protect */ + +%token<tok> TEllipsis /* ... */ +%token<tok> TEndln /* ; or \n */ +%token<tok> TEndblk /* ;; */ +%token<tok> TColon /* : */ +%token<tok> TDot /* . */ +%token<tok> TComma /* , */ +%token<tok> TRet /* -> */ +%token<tok> TUse /* use */ +%token<tok> TPkg /* pkg */ +%token<tok><tok> TSizeof /* sizeof */ + +%token<tok> TIdent +%token<tok> TEof + +%start module + +%type <ty> type structdef uniondef enumdef compoundtype functype funcsig + +%type <tok> asnop cmpop addop mulop shiftop + +%type <node> exprln retexpr expr atomicexpr literal asnexpr lorexpr landexpr borexpr +%type <node> bandexpr cmpexpr addexpr mulexpr shiftexpr prefixexpr postfixexpr +%type <node> funclit arraylit arglist name +%type <node> decl declvariants declbody declcore structelt enumelt unionelt + +%type <nodelist> argdefs structbody enumbody unionbody + +%union { + struct { + Node **nodes; + size_t nnodes; + } nodelist; + struct { + Type **types; + size_t ntypes; + } tylist; + Node *node; + Tok *tok; + Type *ty; +} + + +%% + +module : file + ; + +file : toplev + | file toplev + ; + +toplev + : decl + | use + | package + | typedef + | TEndln + ; + +decl : declvariants TEndln + ; + +use : TUse TIdent TEndln + | TUse TStrlit TEndln + ; + +package : TPkg TIdent TAsn pkgbody TEndblk {} + ; + + +pkgbody : pkgitem + | pkgbody pkgitem + ; + +pkgitem : decl + | type + | visdef + | TEndln + ; + +visdef : TExport TColon + | TProtect TColon + ; + + +declvariants + : TVar declbody {$2->decl.isconst = 0; $$ = $2;} + | TConst declbody {$2->decl.isconst = 1; $$ = $2;} + | TExtern TVar declbody {$3->decl.isconst = 0; $$ = $3;} + | TExtern TConst declbody {$3->decl.isconst = 0; $$ = $3;} + ; + +declbody: declcore TAsn expr {$$ = $1; $1->decl.init = $3;} + | declcore + ; + +declcore: name {$$ = mkdecl(line, mksym(line, $1, mktyvar(line)));} + | name TColon type {$$ = mkdecl(line, mksym(line, $1, $3));} + ; + +name : TIdent {$$ = mkname(line, $1->str);} + | TIdent TDot name {$$ = $3; setns($3, $1->str);} + ; + +typedef : TType TIdent TAsn type TEndln + | TType TIdent TEndln + ; + +type : structdef + | uniondef + | enumdef + | compoundtype + ; + +compoundtype + : functype {$$ = $1;} + | type TOsqbrac TComma TCsqbrac {$$ = mktyslice(line, $1);} + | type TOsqbrac expr TCsqbrac {$$ = mktyarray(line, $1, $3);} + | type TStar {$$ = mktyptr(line, $1);} + | name {$$ = mktynamed(line, $1);} + | TAt TIdent {$$ = mktyparam(line, $2->str);} + ; + +functype: TOparen funcsig TCparen {$$ = $2;} + ; + +funcsig : argdefs {$$ = mktyfunc(line, $1.nodes, $1.nnodes, mktyvar(line));} + | argdefs TRet type {$$ = mktyfunc(line, $1.nodes, $1.nnodes, $3);} + ; + +argdefs : declcore {$$.nodes = NULL; $$.nnodes = 0; nlappend(&$$.nodes, &$$.nnodes, $1);} + | argdefs TComma declcore {nlappend(&$$.nodes, &$$.nnodes, $3);} + ; + +structdef + : TStruct structbody TEndblk {$$ = mktystruct($1->line, $2.nodes, $2.nnodes);} + ; + +structbody + : structelt {$$.nnodes = 0; nlappend(&$$.nodes, &$$.nnodes, $1);} + | structbody structelt {if ($2) {nlappend(&$$.nodes, &$$.nnodes, $2);}} + ; + +structelt + : declcore TEndln {$$ = $1;} + | visdef TEndln {$$ = NULL;} + ; + +uniondef + : TUnion unionbody TEndblk {$$ = mktyunion(line, $2.nodes, $2.nnodes);} + ; + +unionbody + : unionelt {$$.nnodes = 0; nlappend(&$$.nodes, &$$.nnodes, $1);} + | unionbody unionelt {if ($2) {nlappend(&$$.nodes, &$$.nnodes, $2);}} + ; + +unionelt + : TIdent type TEndln {$$ = NULL; die("unionelt impl");} + | visdef TEndln {$$ = NULL;} + ; + +enumdef : TEnum enumbody TEndblk {$$ = mktyenum($1->line, $2.nodes, $2.nnodes);} + ; + +enumbody: enumelt {$$.nnodes = 0; nlappend(&$$.nodes, &$$.nnodes, $1);} + | enumbody enumelt {if ($2) {nlappend(&$$.nodes, &$$.nnodes, $2);}} + ; + +enumelt : TIdent TEndln {$$ = NULL; die("enumelt impl");} + | TIdent TAsn exprln {$$ = NULL; die("enumelt impl");} + ; + +retexpr : TRet exprln {$$ = mkexpr(line, Oret, $2, NULL);} + | exprln + ; + +exprln : expr TEndln + ; + +expr : asnexpr{dump($1, stdout);} + ; + +asnexpr : lorexpr asnop asnexpr {$$ = mkexpr($1->line, binop($2->type), $1, $3, NULL);} + | lorexpr + ; + +asnop : TAsn + | TAddeq /* += */ + | TSubeq /* -= */ + | TMuleq /* *= */ + | TDiveq /* /= */ + | TModeq /* %= */ + | TBoreq /* |= */ + | TBxoreq /* ^= */ + | TBandeq /* &= */ + | TBsleq /* <<= */ + | TBsreq /* >>= */ + ; + +lorexpr : lorexpr TLor landexpr {$$ = mkexpr($1->line, binop($2->type), $1, $3, NULL);} + | landexpr + ; + +landexpr: landexpr TLand borexpr {$$ = mkexpr($1->line, binop($2->type), $1, $3, NULL);} + | borexpr + ; + +borexpr : borexpr TBor bandexpr {$$ = mkexpr($1->line, binop($2->type), $1, $3, NULL);} + | bandexpr + ; + +bandexpr: bandexpr TBand cmpexpr {$$ = mkexpr($1->line, binop($2->type), $1, $3, NULL);} + | cmpexpr + ; + +cmpexpr : cmpexpr cmpop addexpr {$$ = mkexpr($1->line, binop($2->type), $1, $3, NULL);} + | addexpr + ; + +cmpop : TEq | TGt | TLt | TGe | TLe | TNe ; + +addexpr : addexpr addop mulexpr {$$ = mkexpr($1->line, binop($2->type), $1, $3, NULL);} + | mulexpr + ; + +addop : TPlus | TMinus ; + +mulexpr : mulexpr mulop shiftexpr {$$ = mkexpr($1->line, binop($2->type), $1, $3, NULL);} + | shiftexpr + ; + +mulop : TStar | TDiv | TMod + ; + +shiftexpr + : shiftexpr shiftop prefixexpr {$$ = mkexpr($1->line, binop($2->type), $1, $3, NULL);} + | prefixexpr + ; + +shiftop : TBsl | TBsr; + +prefixexpr + : TInc postfixexpr {$$ = mkexpr($1->line, Opreinc, $2, NULL);} + | TDec postfixexpr {$$ = mkexpr($1->line, Opredec, $2, NULL);} + | TStar postfixexpr {$$ = mkexpr($1->line, Oderef, $2, NULL);} + | TBand postfixexpr {$$ = mkexpr($1->line, Oaddr, $2, NULL);} + | TLnot postfixexpr {$$ = mkexpr($1->line, Olnot, $2, NULL);} + | TBnot postfixexpr {$$ = mkexpr($1->line, Obnot, $2, NULL);} + | TMinus postfixexpr {$$ = mkexpr($1->line, Oneg, $2, NULL);} + | TPlus postfixexpr {$$ = $2;} + | postfixexpr + ; + +postfixexpr + : postfixexpr TDot TIdent { + $$ = mkexpr($1->line, Omemb, $1, mkname($3->line, $3->str), NULL); + } + | postfixexpr TInc {$$ = mkexpr($1->line, Opostinc, $1, NULL);} + | postfixexpr TDec {$$ = mkexpr($1->line, Opostdec, $1, NULL);} + | postfixexpr TOsqbrac expr TCsqbrac {$$ = mkexpr($1->line, Oidx, $1, $3);} + | postfixexpr TOsqbrac expr TComma expr TCsqbrac { + $$ = mkexpr($1->line, Oslice, $1, $3, $5, NULL); + } + | postfixexpr TOparen arglist TCparen {$$ = mkexpr($1->line, Ocall, $1, $3);} + | atomicexpr + ; + +arglist : asnexpr + | arglist TComma asnexpr + ; + +atomicexpr + : TIdent {$$ = mkexpr(line, Ovar, mkname(line, $1->str), NULL);} + | literal + | TOparen expr TCparen {$$ = $2;} + | TSizeof atomicexpr {$$ = mkexpr($1->line, Osize, $2, NULL);} + ; + +literal : funclit {$$ = $1;} + | arraylit {$$ = $1;} + | TStrlit {$$ = mkstr($1->line, $1->str);} + | TIntlit {$$ = mkint($1->line, strtol($1->str, NULL, 0));} + | TChrlit {$$ = mkchar($1->line, *$1->str);} /* FIXME: expand escapes, unicode */ + | TFloatlit {$$ = mkfloat($1->line, strtod($1->str, NULL));} + | TBoollit {$$ = mkbool($1->line, !strcmp($1->str, "true"));} + ; + +funclit : TObrace params TEndln blockbody TCbrace {$$ = NULL; die("unimpl funclit");} + ; + +params : declcore + | params TComma declcore + ; + +arraylit : TOsqbrac arraybody TCsqbrac {$$ = NULL; die("Unimpl arraylit");} + ; + +arraybody + : expr + | arraybody TComma expr + ; + +stmt : retexpr + | label + | ifstmt + ; + +ifstmt : TIf exprln blockbody elifblocks TElse block + | TIf exprln blockbody elifblocks TEndblk + | TIf exprln blockbody TElse block + | TIf exprln block + ; + +elifblocks + : TElif exprln blockbody + | elifblocks TElif exprln blockbody + ; + +block : blockbody TEndblk + ; + +blockbody + : stmt + | blockbody stmt + ; + +label : TColon TIdent + ; + +%% + +void yyerror(const char *s) +{ + fprintf(stderr, "%d: %s", line, s); + if (curtok->str) + fprintf(stderr, " near %s", curtok->str); + fprintf(stderr, "\n"); +} + +Op binop(int tt) +{ + Op o; + switch (tt) { + case TPlus: o = Oadd; break; + case TMinus: o = Osub; break; + case TStar: o = Omul; break; + case TDiv: o = Odiv; break; + case TMod: o = Omod; break; + case TAsn: o = Oasn; break; + case TAddeq: o = Oaddeq; break; + case TSubeq: o = Osubeq; break; + case TMuleq: o = Omuleq; break; + case TDiveq: o = Odiveq; break; + case TModeq: o = Omodeq; break; + case TBoreq: o = Oboreq; break; + case TBxoreq: o = Obxoreq; break; + case TBandeq: o = Obandeq; break; + case TBsleq: o = Obsleq; break; + case TBsreq: o = Obsreq; break; + case TBor: o = Obor; break; + case TBxor: o = Obxor; break; + case TBand: o = Oband; break; + case TBsl: o = Obsl; break; + case TBsr: o = Obsr; break; + case TEq: o = Oeq; break; + case TGt: o = Ogt; break; + case TLt: o = Olt; break; + case TGe: o = Oge; break; + case TLe: o = Ole; break; + case TNe: o = One; break; + case TLor: o = Olor; break; + case TLand: o = Oland; break; + default: + die("Unimplemented binop\n"); + break; + } + return o; +} + diff --git a/parse/lits.def b/parse/lits.def new file mode 100644 index 0000000..8ee460a --- /dev/null +++ b/parse/lits.def @@ -0,0 +1,7 @@ +L(Lchr) +L(Lbool) +L(Lint) +L(Lflt) +L(Lstr) +L(Lfunc) +L(Larray) diff --git a/parse/main.c b/parse/main.c new file mode 100644 index 0000000..2ab0d61 --- /dev/null +++ b/parse/main.c @@ -0,0 +1,55 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <ctype.h> +#include <string.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "parse.h" + +Node *file; +char *outfile; + +static void usage(char *prog) +{ + printf("%s [-h] [-o outfile] inputs\n", prog); + printf("\t-h\tPrint this help\n"); + printf("\t-o\tOutput to outfile\n"); +} + +int main(int argc, char **argv) +{ + int opt; + int i; + + while ((opt = getopt(argc, argv, "ho:")) != -1) { + switch (opt) { + case 'o': + outfile = optarg; + break; + case 'h': + default: + usage(argv[0]); + exit(0); + break; + } + } + + for (i = optind; i < argc; i++) { + tokinit(argv[i]); + file = mkfile(argv[i]); + yyparse(); + gen(); + } + + return 0; +} + +void gen() +{ + printf("GEN!\n"); +} diff --git a/parse/names.c b/parse/names.c new file mode 100644 index 0000000..e3f626f --- /dev/null +++ b/parse/names.c @@ -0,0 +1,56 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <ctype.h> +#include <string.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "parse.h" + +char *optab[] = { +#define O(op) #op, +#include "ops.def" +#undef O +}; + +char *nodetab[] = { +#define N(nt) #nt, +#include "nodes.def" +#undef N +}; + +char *littab[] = { +#define L(lt) #lt, +#include "lits.def" +#undef L +}; + +char *tidtab[] = { +#define Ty(t) #t, +#include "types.def" +#undef Ty +}; + +char *opstr(Op o) +{ + return optab[o]; +} + +char *nodestr(Ntype nt) +{ + return nodetab[nt]; +} + +char *litstr(Littype lt) +{ + return littab[lt]; +} + +char *tidstr(Ty tid) +{ + return tidtab[tid]; +} diff --git a/parse/node.c b/parse/node.c new file mode 100644 index 0000000..1e2683c --- /dev/null +++ b/parse/node.c @@ -0,0 +1,181 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <ctype.h> +#include <string.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "parse.h" + +static Node *mknode(int line, Ntype nt) +{ + Node *n; + + n = zalloc(sizeof(Node)); + n->type = nt; + n->line = line; + return n; +} + +Node *mkfile(char *name) +{ + Node *n; + + n = mknode(-1, Nfile); + n->file.name = strdup(name); + return n; +} + +Node *mkuse(int line, char *use, int islocal) +{ + Node *n; + + n = mknode(line, Nuse); + n->use.name = strdup(use); + n->use.islocal = islocal; + + return n; +} + +Node *mkexpr(int line, Op op, ...) +{ + Node *n; + va_list ap; + Node *arg; + + n = mknode(line, Nexpr); + n->expr.op = op; + va_start(ap, op); + while ((arg = va_arg(ap, Node*)) != NULL) + nlappend(&n->expr.args, &n->expr.nargs, arg); + va_end(ap); + + return n; +} + +Node *mkif(int line, Node *cond, Node *iftrue, Node *iffalse) +{ + Node *n; + + n = mknode(line, Nifstmt); + n->ifstmt.cond = cond; + n->ifstmt.iftrue = iftrue; + n->ifstmt.iffalse = iffalse; + + return n; +} + +Node *mkloop(int line, Node *init, Node *cond, Node *incr, Node *body) +{ + Node *n; + + n = mknode(line, Nloopstmt); + n->loopstmt.init = init; + n->loopstmt.cond = init; + n->loopstmt.incr = incr; + n->loopstmt.body = body; + + return n; +} + +Node *mkstr(int line, char *val) +{ + Node *n; + + n = mknode(line, Nlit); + n->lit.littype = Lstr; + n->lit.strval = strdup(val); + + return n; +} + +Node *mkint(int line, uint64_t val) +{ + Node *n; + + n = mknode(line, Nlit); + n->lit.littype = Lint; + n->lit.intval = val; + + return n; +} + +Node *mkchar(int line, uint32_t val) +{ + Node *n; + + n = mknode(line, Nlit); + n->lit.littype = Lchr; + n->lit.chrval = val; + + return n; +} + +Node *mkfloat(int line, double val) +{ + Node *n; + + n = mknode(line, Nlit); + n->lit.littype = Lflt; + n->lit.fltval = val; + + return n; +} + +Node *mkname(int line, char *name) +{ + Node *n; + + n = mknode(line, Nname); + n->name.nparts = 1; + n->name.parts = xalloc(sizeof(char*)); + n->name.parts[0] = strdup(name); + + return n; +} + +Node *mkdecl(int line, Sym *sym) +{ + die("Fixme: mkdecl"); + return NULL; +} + +void setns(Node *n, char *name) +{ + int i; + + n->name.nparts++; + n->name.parts = xrealloc(n->name.parts, n->name.nparts); + for (i = n->name.nparts - 1; i > 0; i++) + n->name.parts[i] = n->name.parts[i-1]; + n->name.parts[0] = strdup(name); +} + +Node *mkbool(int line, int val) +{ + Node *n; + + n = mknode(line, Nlit); + n->lit.littype = Lbool; + n->lit.boolval = val; + + return n; +} + +Sym *mksym(int line, Node *name, Type *ty) +{ + die("Fixme: mksym"); + return NULL; +} + +void nlappend(Node ***nl, size_t *len, Node *n) +{ + *nl = xrealloc(nl, (*len + 1)*sizeof(Node*)); + (*nl)[*len] = n; + (*len)++; +} diff --git a/parse/nodes.def b/parse/nodes.def new file mode 100644 index 0000000..3fb771f --- /dev/null +++ b/parse/nodes.def @@ -0,0 +1,9 @@ +N(Nfile) +N(Nblock) +N(Nifstmt) +N(Nloopstmt) +N(Nuse) +N(Nexpr) +N(Nlit) +N(Nname) +N(Ndecl) diff --git a/parse/ops.def b/parse/ops.def new file mode 100644 index 0000000..8315c63 --- /dev/null +++ b/parse/ops.def @@ -0,0 +1,51 @@ +O(Obad) +O(Oadd) +O(Osub) +O(Omul) +O(Odiv) +O(Omod) +O(Oneg) +O(Obor) +O(Oband) +O(Obxor) +O(Obsl) +O(Obsr) +O(Obnot) +O(Opreinc) +O(Opostinc) +O(Opredec) +O(Opostdec) +O(Oaddr) +O(Oderef) +O(Onegl) +O(Olor) +O(Oland) +O(Olnot) +O(Oeq) +O(One) +O(Ogt) +O(Oge) +O(Olt) +O(Ole) +O(Oasn) +O(Oaddeq) +O(Osubeq) +O(Omuleq) +O(Odiveq) +O(Omodeq) +O(Oboreq) +O(Obandeq) +O(Obxoreq) +O(Obsleq) +O(Obsreq) +O(Oidx) +O(Oslice) +O(Omemb) +O(Osize) +O(Ocall) +O(Ocast) +O(Oret) +O(Ogoto) +O(Ovar) +O(Olit) +O(Olbl) diff --git a/parse/parse.h b/parse/parse.h new file mode 100644 index 0000000..1376c4a --- /dev/null +++ b/parse/parse.h @@ -0,0 +1,210 @@ + +typedef unsigned char uchar; +typedef struct Tok Tok; +typedef struct Node Node; +typedef struct Type Type; +typedef struct Stab Stab; +typedef struct Sym Sym; + +typedef enum { +#define O(op) op, +#include "ops.def" +#undef O +} Op; + +typedef enum { +#define N(nt) nt, +#include "nodes.def" +#undef N +} Ntype; + +typedef enum { +#define L(lt) lt, +#include "lits.def" +#undef L +} Littype; + +typedef enum { +#define Ty(t) t, +#include "types.def" +#undef Ty +} Ty; + +struct Tok { + int type; + int line; + char *str; +}; + +struct Stab { + int ntypes; + Type **types; + int nsyms; + Sym **syms; +}; + +struct Sym { + Node *name; + Type *type; +}; + +struct Type { + Ty type; + int tid; + union { + Node *name; /* Tyname: unresolved name */ + Type **fnsub; /* Tyfunc: return, args */ + Type **tusub; /* Tytuple: element types */ + Type *pbase; /* Typtr: pointer target */ + Type *sbase; /* Tyslice: slice target */ + struct { /* Tyarray: array target and size */ + Type *abase; + Node *asize; + }; + char *pname; /* Typaram: name of type parameter */ + Node **sdecls; /* Tystruct: decls in struct */ + Node **udecls; /* Tyunion: decls in union */ + Node **edecls; /* Tyenum: decls in enum */ + }; +}; + +struct Node { + int line; + int type; + union { + struct { + char *name; + size_t nstmts; + Node **stmts; + Stab **globals; + } file; + + struct { + Op op; + int isconst; + size_t nargs; + Node **args; + } expr; + + struct { + size_t nparts; + char **parts; + } name; + + struct { + int islocal; + char *name; + } use; + + struct { + Littype littype; + Type *type; + union { + uint64_t intval; + double fltval; + uint32_t chrval; + char *strval; + int boolval; + }; + } lit; + + struct { + Node *init; + Node *cond; + Node *incr; + Node *body; + } loopstmt; + + struct { + Node *cond; + Node *iftrue; + Node *iffalse; + } ifstmt; + + struct { + Stab *scope; + size_t nstmts; + Node **stmts; + } block; + + struct { + Sym *sym; + Node *init; + int isconst; + } decl; + }; +}; + +/* globals */ +extern char *filename; +extern int line; +extern int ignorenl; +extern Tok *curtok; +extern Node *file; + +/* util functions */ +void *zalloc(size_t size); +void *xalloc(size_t size); +void *xrealloc(void *p, size_t size); +void die(char *msg, ...); +void fatal(int line, char *fmt, ...); + +/* parsing etc */ +void tokinit(char *file); +int yylex(void); +int yyparse(void); + +/* stab creation */ +Stab *mkstab(); +Stab *stput(Sym *decl); +Sym *stget(char *name); +Sym *mksym(int line, Node *name, Type *ty); + +/* type ccreation */ +Type *mktyvar(int line); +Type *mktyparam(int line, char *name); +Type *mktynamed(int line, Node *name); +Type *mktyarray(int line, Type *base, Node *sz); +Type *mktyslice(int line, Type *base); +Type *mktyptr(int line, Type *base); +Type *mktyfunc(int line, Node **args, size_t nargs, Type *ret); +Type *mktystruct(int line, Node **decls, size_t ndecls); +Type *mktyunion(int line, Node **decls, size_t ndecls); +Type *mktyenum(int line, Node **decls, size_t ndecls); + +void tlappend(Type ***tl, int *len, Type *t); + +/* tree creation */ +Node *mkfile(char *name); +Node *mkuse(int line, char *use, int islocal); +Node *mkexpr(int line, Op op, ...); /* NULL terminated */ +Node *mklit(int line, Littype lt, void *val); +Node *mkif(int line, Node *cond, Node *iftrue, Node *iffalse); +Node *mkloop(int line, Node *init, Node *cond, Node *incr, Node *body); + +Node *mkbool(int line, int val); +Node *mkint(int line, uint64_t val); +Node *mkchar(int line, uint32_t val); +Node *mkstr(int line, char *s); +Node *mkfloat(int line, double flt); +Node *mkfunc(int line, Node **args, Node *body); +Node *mkarray(int line, Node **vals); +Node *mkname(int line, char *name); +Node *mkdecl(int line, Sym *sym); + + +void addstmt(Node *file, Node *stmt); +void setns(Node *n, char *name); + +/* debug */ +void dump(Node *t, FILE *fd); +char *opstr(Op o); +char *nodestr(Ntype nt); +char *litstr(Littype lt); +char *tidstr(Ty tid); + +/* convenience macro */ +void nlappend(Node ***nl, size_t *len, Node *n); + +/* backend functions */ +void gen(); diff --git a/parse/tok.c b/parse/tok.c new file mode 100644 index 0000000..54a4901 --- /dev/null +++ b/parse/tok.c @@ -0,0 +1,488 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <ctype.h> +#include <string.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <err.h> +#include <unistd.h> + +#include "parse.h" + +#include "gram.h" + +char *filename; +int line; +int ignorenl; +Tok *curtok; + +static int fidx; +static int fbufsz; +static char *fbuf; + +static int peekn(int n) +{ + if (fidx + n >= fbufsz) + return '\0'; + else + return fbuf[fidx]; +} + +static int peek() +{ + return peekn(0); +} + +static int next() +{ + int c; + + c = peek(); + fidx++; + return c; +} + +void unget() +{ + fidx--; + assert(fidx >= 0); +} + +int match(char c) +{ + if (peek() == c) { + next(); + return 1; + } else { + return 0; + } +} + +Tok *mktok(int tt) +{ + Tok *t; + + t = zalloc(sizeof(Tok)); + t->type = tt; + t->line = line; + return t; +} + +static int identchar(int c) +{ + return isalnum(c) || c == '_'; +} + +static void eatcomment() +{ + int depth; + int startln; + int c; + + depth = 0; + startln = line; + while (1) { + c = next(); + switch (c) { + case '/': + if (peekn(1) == '*') + depth++; + break; + case '*': + if (peekn(1) == '/') + depth--; + break; + case '\n': + line++; + break; + case EOF: + fatal(line, "File ended within comment starting at line %d", startln); + break; + } + } +} + +void eatspace() +{ + int c; + + while (1) { + c = peek(); + if ((!ignorenl && c == '\n')) + break; + else if (isspace(c)) + next(); + else if (c == '/' && peekn(1) == '*') + eatcomment(c); + else + break; + } +} + +int kwd(char *s) +{ + int i; + struct {char* kw; int tt;} kwmap[] = { + {"type", TType}, + {"for", TFor}, + {"while", TWhile}, + {"if", TIf}, + {"else", TElse}, + {"elif", TElif}, + {"match", TMatch}, + {"default", TDefault}, + {"goto", TGoto}, + {"enum", TEnum}, + {"struct", TStruct}, + {"union", TUnion}, + {"const", TConst}, + {"var", TVar}, + {"extern", TExtern}, + {"export", TExport}, + {"protect", TProtect}, + {"use", TUse}, + {"pkg", TPkg}, + {"sizeof", TSizeof}, + {"true", TBoollit}, + {"false", TBoollit}, + {NULL, 0} + }; + + for (i = 0; kwmap[i].kw; i++) + if (!strcmp(kwmap[i].kw, s)) + return kwmap[i].tt; + + return TIdent; +} + +Tok *kwident() +{ + char buf[1024]; + char c; + int i; + Tok *t; + + i = 0; + for (c = peek(); i < 1023 && identchar(c); c = peek()) { + next(); + buf[i++] = c; + } + buf[i] = '\0'; + t = mktok(kwd(buf)); + t->str = strdup(buf); + return t; +} + +Tok *strlit() +{ + Tok *t; + int sstart; /* start of string within input buf */ + int c; + + assert(next() == '"'); + + sstart = fidx; + while (1) { + c = next(); + /* we don't unescape here, but on output */ + if (c == '"') + break; + else if (c == '\\') + c = next(); + + if (c == '\0') + fatal(line, "Unexpected EOF within string"); + else if (c == '\n') + fatal(line, "Newlines not allowed in strings"); + }; + t = mktok(TStrlit); + t->str = strndup(&fbuf[sstart], fidx - sstart); + return t; +} + +Tok *charlit() +{ + Tok *t; + int sstart; /* start of string within input buf */ + int c; + + assert(next() == '\''); + + sstart = fidx; + while (1) { + c = next(); + /* we don't unescape here, but on output */ + if (c == '\'') + break; + else if (c == '\\') + c = next(); + + if (c == '\0') + fatal(line, "Unexpected EOF within char lit"); + else if (c == '\n') + fatal(line, "Newlines not allowed in char lit"); + }; + t = mktok(TChrlit); + t->str = strndup(&fbuf[sstart], fidx - sstart); + return t; +} + +Tok *oper() +{ + int tt; + char c; + + c = next(); + switch (c) { + case '{': tt = TObrace; break; + case '}': tt = TCbrace; break; + case '(': tt = TOparen; break; + case ')': tt = TCparen; break; + case '[': tt = TOsqbrac; break; + case ']': tt = TCsqbrac; break; + case ',': tt = TComma; break; + case ':': tt = TColon; break; + case '~': tt = TBnot; break; + case ';': + if (match(';')) + tt = TEndblk; + else + tt = TEndln; + break; + case '.': + if (match('.')) { + if (match('.')) + tt = TEllipsis; + else + unget(); + } else { + tt = TDot; + } + break; + case '+': + if (match('=')) + tt = TAddeq; + else if (match('+')) + tt = TInc; + else + tt = TPlus; + break; + case '-': + if (match('=')) + tt = TSubeq; + else if (match('+')) + tt = TDec; + else if (match('>')) + tt = TRet; + else + tt = TMinus; + break; + case '*': + if (match('=')) + tt = TMuleq; + else + tt = TStar; + break; + case '/': + if (match('=')) + tt = TDiveq; + else + tt = TDiv; + break; + case '%': + if (match('=')) + tt = TModeq; + else + tt = TMod; + break; + case '=': + if (match('=')) + tt = TEq; + else + tt = TAsn; + break; + case '|': + if (match('=')) + tt = TBoreq; + else if (match('|')) + tt = TLor; + else + tt = TBor; + break; + case '&': + if (match('=')) + tt = TBandeq; + else if (match('|')) + tt = TLand; + else + tt = TBand; + break; + case '^': + if (match('=')) + tt = TBxoreq; + else + tt = TBxor; + break; + case '<': + if (match('=')) { + tt = TLe; + } else if (match('<')) { + if (match('=')) + tt = TBsleq; + else + tt = TBsl; + } else { + tt = TLt; + } + break; + case '>': + if (match('=')) { + tt = TGe; + } else if (match('<')) { + if (match('=')) + tt = TBsreq; + else + tt = TBsr; + } else { + tt = TGt; + } + break; + + case '!': + if (match('=')) + tt = TNe; + else + tt = TLnot; + break; + default: + tt = TError; + fatal(line, "Junk character %c", c); + break; + } + return mktok(tt); +}; + +Tok *number(int base) +{ + Tok *t; + int start; + char *endp; + int c; + int isfloat; + + t = NULL; + isfloat = 0; + start = fidx; + for (c = peek(); isxdigit(c) || c == '.'; c = peek()) { + next(); + if (c == '.') + isfloat = 1; + } + + /* we only support base 10 floats */ + if (isfloat && base == 10) { + strtod(&fbuf[start], &endp); + if (endp == &fbuf[fidx]) { + t = mktok(TFloatlit); + t->str = strndup(&fbuf[start], fidx - start); + } + } else { + strtol(&fbuf[start], &endp, base); + if (endp == &fbuf[fidx]) { + t = mktok(TIntlit); + t->str = strndup(&fbuf[start], fidx - start); + } + } + + return t; +} + +Tok *numlit() +{ + Tok *t; + + /* check for 0x or 0b prefix */ + if (match('0')) { + if (match('x')) + t = number(16); + else if (match('b')) + t = number(2); + else + t = number(10); + } else { + t = number(10); + } + + return t; +} + +Tok *toknext() +{ + Tok *t; + int c; + + eatspace(); + c = peek(); + if (c == '\0') { + t = mktok(0); + } else if (c == '\n') { + line++; + next(); + t = mktok(TEndln); + } else if (isalpha(c) || c == '_') { + t = kwident(); + } else if (c == '"') { + t = strlit(); + } else if (c == '\'') { + t = charlit(); + } else if (isdigit(c)) { + t = numlit(); + } else { + t = oper(); + } + + if (!t || t->type == TError) + fatal(line, "Unable to parse token starting with %c", c); + + return t; +} + +void tokinit(char *file) +{ + int fd; + int n; + int nread; + + + fd = open(file, O_RDONLY); + if (fd == -1) + err(errno, "Unable to open file %s", file); + fbuf = malloc(4096); + while (1) { + n = read(fd, fbuf, 4096); + if (n < 0) + fatal(errno, "Error reading file %s", file); + if (n == 0) + break; + if (!fbuf) + die("Out of memory reading %s", file); + nread += n; + fbuf = realloc(fbuf, nread + 4096); + } + + fbufsz = nread; + line = 1; + fidx = 0; + filename = strdup(file); +} + +int yylex() +{ + curtok = toknext(); + yylval.tok = curtok; + return curtok->type; +} diff --git a/parse/type.c b/parse/type.c new file mode 100644 index 0000000..f80edca --- /dev/null +++ b/parse/type.c @@ -0,0 +1,157 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <ctype.h> +#include <string.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "parse.h" + +typedef struct Typename Typename; +struct Typename { + Ty ty; + char *name; +}; + +Typename typenames[] = { + {Tyvoid, "void"}, + {Tychar, "char"}, + {Tybyte, "byte"}, + {Tyint8, "int8"}, + {Tyint16, "int16"}, + {Tyint32, "int32"}, + {Tyint64, "int64"}, + {Tyuint8, "uint8"}, + {Tyuint16, "uint16"}, + {Tyuint32, "uint32"}, + {Tyuint64, "uint64"}, + {Tyfloat32, "float32"}, + {Tyfloat64, "float64"}, + {Tybad, NULL} +}; + + +static int nexttid = 0; +static Type *mktype(Ty ty) +{ + Type *t; + + t = xalloc(sizeof(Type)); + t->type = ty; + t->tid = nexttid++; + return t; +} + +Type *mktyvar(int line) +{ + Type *t; + + t = mktype(Tyvar); + return t; +} + +Type *mktyparam(int line, char *name) +{ + Type *t; + + t = mktype(Tyvar); + t->pname = strdup(name); + return t; +} + +Type *mktynamed(int line, Node *name) +{ + int i; + Type *t; + + /* is it a built in type? */ + if (name->name.nparts == 1) + for (i = 0; typenames[i].name; i++) + if (!strcmp(typenames[i].name, name->name.parts[0])) + return mktype(typenames[i].ty); + + /* if not, resolve it in the type inference stage */ + t = mktype(Tyname); + t->name = name; + return t; +} + +Type *mktyarray(int line, Type *base, Node *sz) +{ + Type *t; + + t = mktype(Tyarray); + t->abase = base; + t->asize = sz; + + return t; +} + +Type *mktyslice(int line, Type *base) +{ + Type *t; + + t = mktype(Tyslice); + t->sbase = base; + return t; +} + +Type *mktyptr(int line, Type *base) +{ + Type *t; + + t = mktype(Typtr); + t->pbase = base; + return t; +} + +Type *mktyfunc(int line, Node **args, size_t nargs, Type *ret) +{ + Type *t; + Type **sub; + + t = mktype(Tyfunc); + sub = xalloc((1 + nargs)*sizeof(Type)); + sub[0] = ret; + die("pull out subtypes for fn"); + t->fnsub = sub; + return t; +} + +Type *mktystruct(int line, Node **decls, size_t ndecls) +{ + Type *t; + + t = mktype(Tystruct); + t->sdecls = decls; + return t; +} + +Type *mktyunion(int line, Node **decls, size_t ndecls) +{ + Type *t; + + t = mktype(Tyunion); + t->udecls = decls; + return t; +} + +Type *mktyenum(int line, Node **decls, size_t ndecls) +{ + Type *t; + + t = mktype(Tyenum); + t->edecls = decls; + return t; +} + +void tlappend(Type ***tl, int *len, Type *t) +{ + *tl = xrealloc(tl, (*len + 1)*sizeof(Type*)); + (*tl)[*len] = t; + (*len)++; +} diff --git a/parse/types.def b/parse/types.def new file mode 100644 index 0000000..aea6614 --- /dev/null +++ b/parse/types.def @@ -0,0 +1,41 @@ +Ty(Tybad) +Ty(Tyvoid) + +/* start integer types. + * Keep them ordered between start + * and end for faster + * comparisons.*/ +Ty(Tybool) +Ty(Tychar) + +Ty(Tyint8) +Ty(Tyint16) +Ty(Tyint) +Ty(Tyint32) +Ty(Tyint64) +Ty(Tylong) + +Ty(Tybyte) +Ty(Tyuint8) +Ty(Tyuint16) +Ty(Tyuint) +Ty(Tyuint32) +Ty(Tyuint64) +Ty(Tyulong) +/*end integer types*/ +Ty(Tyfloat32) +Ty(Tyfloat64) +Ty(Tyvalist) +/*end numerical types*/ +Ty(Typtr) +Ty(Tyslice) +Ty(Tyarray) +Ty(Tyfunc) +Ty(Tytuple) +Ty(Tyvar) +Ty(Typaram) +Ty(Tyname) +Ty(Tystruct) +Ty(Tyunion) +Ty(Tyenum) + diff --git a/parse/util.c b/parse/util.c new file mode 100644 index 0000000..f68d7f9 --- /dev/null +++ b/parse/util.c @@ -0,0 +1,66 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <ctype.h> +#include <string.h> +#include <assert.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "parse.h" + +void *zalloc(size_t sz) +{ + void *mem; + + mem = calloc(1, sz); + if (!mem) + die("Out of memory"); + return mem; +} + + +void *xalloc(size_t sz) +{ + void *mem; + + mem = malloc(sz); + if (!mem) + die("Out of memory"); + return mem; +} + +void *xrealloc(void *mem, size_t sz) +{ + mem = realloc(mem, sz); + if (!mem) + die("Out of memory"); + return mem; +} + +void die(char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + vfprintf(stderr, msg, ap); + fprintf(stderr, "\n"); + va_end(ap); + abort(); +} + +void fatal(int line, char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + fprintf(stderr, "%s:%d: ", filename, line); + vfprintf(stderr, msg, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(1); +} |