ref: 72abaa282749e37df7831959b1a344664b1827f3
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 *lexfile = "<stdin>"; int yyparse(void); void yyerror(char*); %} %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 %token TYPE NAME NUM %token <sval> NAME; %token <ival> NUM %type<nod> arg expr logexpr shifexpr addexpr mulexpr %type<nod> unary sufexpr compexpr %type<lst> args %type<typ> type %% prog : prog top | top top : FUNC NAME '(' args ')' return '{' stmts '}' | MOD NAME ';' | USE NAME ';' | def ';' sdecls : | sdecls NAME ':' type ';' def : DEF NAME NAME { } | DEF NAME STRUCT '{' sdecls '}' { } type : NAME { $$ = nil; } | type '[' ']' { $$ = mktyslice($1); } | type '[' NUM ']' { $$ = mktyarray($1, mklit($3)); } | type '!' { $$ = $1; $$->linear = 1; } return : ARROWR type | unary : NUM { $$ = mkexpr(Olit, mklit($1), nil); } | NAME { $$ = mkexpr(Ovar, mksym($1), nil); } | ARROWL unary { $$ = mkexpr(Orcv, $2, nil); } | '(' expr ')' { $$ = $2; } sufexpr : unary '--' { $$ = mkexpr(Odec, $1, nil); } | unary '++' { $$ = mkexpr(Oinc, $1, nil); } | unary { $$ = $1; } mulexpr : mulexpr '*' sufexpr { $$ = mkexpr(Omul, $1, $3); } | mulexpr '/' sufexpr { $$ = mkexpr(Odiv, $1, $3); } | mulexpr '%' sufexpr { $$ = mkexpr(Omod, $1, $3); } | sufexpr { $$ = $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 : | stmts stmt decl : NAME ':' type | NAME ':' '=' expr stmt : expr ';' | '{' stmts '}' | decl ';' | FOR '(' expr ')' stmt | FOR '(' expr ';' expr ';' expr ')' stmt | IF '(' expr ')' stmt ELSE stmt | IF '(' expr ')' stmt arg : NAME ':' type { $$ = mkdecl($1, $3, nil); } args : { $$ = ZL; } | arg { $$ = append(ZL, $1); } | args ',' arg { $$ = append($1, $3); } %% struct { char *s; int type; } keytab[] = { "fn", FUNC, "type", DEF, "if", IF, "for", FOR, "mod", MOD, "use", USE, "&&", AND, "||", OR, "!=", NOTEQ, "==", EQ, "<=", LTEQ, ">=", GTEQ, "<<", SHIFTR, ">>", SHIFTL, "struct", STRUCT, "else", ELSE, "->", ARROWR, "→", ARROWR, "<-", ARROWL, "←", ARROWL, }; 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); } int yylex2(void) { static char buf[200]; int c; int i; 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; } switch(c){ case ';': case '=': case '{': case '}': case '[': case ']': case '(': case ')': case '+': case '-': case '*': case '/': case '%': case ':': case '>': case '<': case ',': case '.': 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) { ARGBEGIN{ case 'd': debug++; break; default: usage(); break; }ARGEND; if(argc > 0) usage(); bin = Bfdopen(0, OREAD); goteof = 0; while(!goteof) yyparse(); Bterm(bin); exits(nil); }