ref: e01f61f0d55b37630264e8d74107199752a6e76f
dir: /n.y/
%{ #include <u.h> #include <libc.h> #include <bio.h> #include <ctype.h> #include "dat.h" #include "fns.h" int goteof; int lexline; char *modname; char *lexfile = "<stdin>"; int yyparse(void); void yyerror(char*); Nlst toplevel; void loaduse(char*) { fprint(2, "not implement: loaduse\n"); } %} %union { char *sval; long ival; Typ *typ; Nod *nod; Nlst lst; } %token FUNC DEF IF FOR MOD USE OR AND NOTEQ EQ SHIFTL SHIFTR STRUCT ELSE ARROWR ARROWL GTEQ LTEQ INC DEC %token TYPE NAME NUM %token <sval> NAME; %token <ival> NUM %type<nod> defarg expr logexpr shifexpr addexpr mulexpr %type<nod> unary prefexpr sufexpr compexpr top stmt %type<nod> decl %type<lst> defargs prog stmts args %type<typ> type return %% file : prog { toplevel = $1; } prog : prog top { $$ = append($1, $2); } | top { $$ = append(ZL, $1); } top : FUNC NAME '(' defargs ')' return '{' stmts '}' { $$ = mkfunc($2, $4, $6, $8); } | MOD NAME ';' { $$ = nil; modname = $2; } | USE NAME ';' { $$ = nil; loaduse($2); } | def ';' { $$ = nil; } sdecls : | sdecls NAME ':' type ';' def : DEF NAME type { } | DEF NAME STRUCT '{' sdecls '}' { } type : NAME { $$ = mktype($1, Tunkn); } | type '[' ']' { $$ = mktyslice($1); } | type '[' NUM ']' { $$ = mktyarray($1, mkintlit($3)); } | type '!' { $$ = $1; $$->linear = 1; } return : ARROWR type { $$ = $2; } | { $$ = mktype("void", Tvoid); } unary : NUM { $$ = mkexpr(Olit, mkintlit($1), nil); } | NAME { $$ = mkexpr(Ovar, mksym($1), nil); } | '"' NAME '"' { $$ = mkstrlit($2); } | '(' expr ')' { $$ = $2; } sufexpr : sufexpr DEC { $$ = mkexpr(Odec, $1, nil); } | sufexpr INC { $$ = mkexpr(Oinc, $1, nil); } | NAME '(' args ')' { $$ = mkcall($1, $3); } | unary { $$ = $1; } prefexpr : ARROWL sufexpr { $$ = mkexpr(Orcv, $2, nil); } | sufexpr { $$ = $1; } mulexpr : mulexpr '*' prefexpr { $$ = mkexpr(Omul, $1, $3); } | mulexpr '/' prefexpr { $$ = mkexpr(Odiv, $1, $3); } | mulexpr '%' prefexpr { $$ = mkexpr(Omod, $1, $3); } | prefexpr { $$ = $1; } addexpr : addexpr '+' mulexpr { $$ = mkexpr(Oadd, $1, $3); } | addexpr '-' mulexpr { $$ = mkexpr(Osub, $1, $3); } | mulexpr { $$ = $1; } shifexpr : shifexpr SHIFTL addexpr { $$ = mkexpr(Oshl, $1, $3); } | shifexpr SHIFTR addexpr { $$ = mkexpr(Oshr, $1, $3); } | addexpr { $$ = $1; } compexpr : compexpr '>' shifexpr { $$ = mkexpr(Ogt, $1, $3); } | compexpr '<' shifexpr { $$ = mkexpr(Olt, $1, $3); } | compexpr NOTEQ shifexpr { $$ = mkexpr(One, $1, $3); } | compexpr EQ shifexpr { $$ = mkexpr(Oeq, $1, $3); } | compexpr LTEQ shifexpr { $$ = mkexpr(Oge, $1, $3); } | compexpr GTEQ shifexpr { $$ = mkexpr(Ole, $1, $3); } | shifexpr { $$ = $1; } logexpr : logexpr OR compexpr { $$ = mkexpr(Olor, $1, $3); } | logexpr AND compexpr { $$ = mkexpr(Oland, $1, $3); } | compexpr { $$ = $1; } expr : { $$ = nil; } | expr '=' logexpr { $$ = mkexpr(Oasn, $1, $3); } | logexpr { $$ = $1; } stmts : { $$ = ZL; } | stmts stmt { $$ = append($1, $2); } decl : NAME ':' type { $$ = mkdecl($1, $3, nil); } | NAME ':' '=' expr { $$ = mkdecl($1, nil, $4); } | NAME ':' type '=' expr { $$ = mkdecl($1, $3, $5); } stmt : expr ';' { $$ = $1; } | '{' stmts '}' { $$ = mkblk($2); } | decl ';' { $$ = $1; } | FOR '(' unary ARROWL expr ')' stmt { $$ = mkiter($3, $5, $7); } | FOR '(' expr ';' expr ';' expr ')' stmt { $$ = mkfor($3, $5, $7, $9); } | IF '(' expr ')' stmt ELSE stmt { $$ = mkif($3, $5, $7); } | IF '(' expr ')' stmt { $$ = mkif($3, $5, nil); } defarg : NAME ':' type { $$ = mkdecl($1, $3, nil); } defargs : { $$ = ZL; } | defarg { $$ = append(ZL, $1); } | defargs ',' defarg { $$ = append($1, $3); } /* TODO: should be expr */ args : { $$ = ZL; } | logexpr { $$ = append(ZL, $1); } | args ',' logexpr { $$ = append($1, $3); } %% Biobuf *bin; int getch(void) { int c; c = Bgetrune(bin); if(c == Beof){ goteof = 1; return -1; } if(c == '\n') lexline++; return c; } void ungetc(void) { Bungetrune(bin); } void wordlex(char *dst, int n) { Rune c; char *e; for(e = dst + n - UTFmax; dst < e;){ c = getch(); if((c >= Runeself) || isalnum(c)){ dst += runetochar(dst, &c); continue; } ungetc(); break; } if(dst > e - UTFmax*2) yyerror("symbol buffer overrun"); *dst = '\0'; } void yyerror(char *s) { fprint(2, "%d: %s\n", lexline, s); exits(s); } struct { int c; struct { int c; int t; } next[3]; } spectab[] = { '-', { '>', ARROWR, '-', DEC }, '=', { '=', EQ }, '>', { '>', SHIFTR, '=', GTEQ }, '<', { '-', ARROWL, '<', SHIFTL, '=', LTEQ }, '!', { '=', NOTEQ }, '&', { '&', AND }, '|', { '|', OR }, '+', { '+', INC }, }; struct { char *s; int type; } keytab[] = { "fn", FUNC, "type", DEF, "if", IF, "for", FOR, "mod", MOD, "use", USE, "struct", STRUCT, "else", ELSE, "→", ARROWR, "←", ARROWL, }; int yylex2(void) { static char buf[200]; int c, c2; int i, j; Loop: c = getch(); switch(c){ case -1: return -1; case ' ': case '\t': case '\n': goto Loop; case '/': if(getch() != '*'){ ungetc(); goto Loop; } More: while((c = getch()) > 0) if(c == '*') break; if(c != '*') goto Loop; if(getch() == '/') goto Loop; goto More; } if(utfrune("\"';{}[]()*/%:,.", c) != nil) return c; for(i = 0; i < nelem(spectab); i++){ if(c != spectab[i].c) continue; c2 = getch(); for(j = 0; j < 3; j++) if(c2 == spectab[i].next[j].c) return spectab[i].next[j].t; ungetc(); return c; } ungetc(); wordlex(buf, sizeof buf); for(i = 0; i < nelem(keytab); i++) if(strcmp(keytab[i].s, buf) == 0) return keytab[i].type; if(isdigit(buf[0])){ yylval.ival = atoi(buf); return NUM; } yylval.sval = strdup(buf); return NAME; } int debug; int yylex(void) { int c; c = yylex2(); if(!debug) return c; if(c < Runeself) fprint(2, "%c\n", c); else if(c == NAME) fprint(2, "NAME %s\n", yylval.sval); else if(c == TYPE) fprint(2, "TYPE %s\n", yylval.sval); else if(c == NUM) fprint(2, "NUM %ld\n", yylval.ival); return c; } void usage(void) { fprint(2, "usage: [-d] %s\n", argv0); exits("usage"); } void main(int argc, char **argv) { int ast; ast = 0; ARGBEGIN{ case 'a': ast++; break; case 'd': debug++; break; default: usage(); break; }ARGEND; if(argc > 0) usage(); astfmtinstall(); bin = Bfdopen(0, OREAD); goteof = 0; while(!goteof) yyparse(); Bterm(bin); if(ast) print("%L\n", toplevel); else print("%M\n", toplevel); exits(nil); }