ref: 97bc549d4b8bf638946ac4ff3b066941bca9a03b
dir: /semblance.y/
%{ #include <u.h> #include <libc.h> #include <ctype.h> #include <bio.h> #include <geometry.h> #include "dat.h" #include "fns.h" %} %union { int type; double val; Symbol *sym; } %token <type> TYPE %token <val> NUMBER %token <sym> VAR CONST BLTIN UNDEF %type <val> expr exprs %type <sym> asgn asgns %right '=' %% top: /* ε */ | list ; list: prog | list prog ; prog: '\n' | decls | asgns | exprs { print("\t%.8g\n", $1); } ; decls: decls decl | decl ; decl: TYPE { decltype = $1; } vars ';' ; vars: VAR { if($1->type != UNDEF) rterror("variable already exists"); $1->type = VAR; $1->u.var.type = decltype; print("%s %s;\n", ctypename(decltype), $1->name); } | vars ',' VAR { if($3->type != UNDEF) rterror("variable already exists"); $3->type = VAR; $3->u.var.type = decltype; print("%s %s;\n", ctypename(decltype), $3->name); } ; asgns: asgns asgn ';' | asgn ';' ; asgn: VAR '=' NUMBER { if($1->type != VAR || $1->u.var.type != TDOUBLE) rterror("illegal assignment"); $1->u.var.dval = $3; $$ = $1; } | VAR '=' VAR { switch($1->type){ default: rterror("illegal assignment"); case VAR: if($1->u.var.type != $3->u.var.type) rterror("illegal assignment"); switch($1->u.var.type){ case TDOUBLE: $1->u.var.dval = $3->u.var.dval; break; case TPOINT: case TVECTOR: case TNORMAL: case TQUAT: $1->u.var.pval = $3->u.var.pval; break; } $$ = $1; break; } } ; exprs: exprs expr ';' | expr ';' ; expr: NUMBER | VAR { Point3 *p; switch($1->type){ case UNDEF: rterror("undefined variable"); case CONST: $$ = $1->u.val; break; case VAR: switch($1->u.var.type){ case TDOUBLE: $$ = $1->u.var.dval; break; case TPOINT: case TVECTOR: case TNORMAL: $$ = -1; p = &$1->u.var.pval; print("[%g %g %g %g]\n", p->x, p->y, p->z, p->w); break; } break; } } ; %% int decltype; Biobuf *bin; int lineno; void yyerror(char *msg) { fprint(2, "%s at line %d\n", msg, lineno); } void rterror(char *msg) { fprint(2, "%s at line %d\n", msg, lineno); } int yylex(void) { Symbol *s; char sname[256], *p; Rune r; int t; while((r = Bgetrune(bin)) == ' ' || r == '\t') ; if(r == Beof) return 0; if(r == '.' || isdigitrune(r)){ Bungetrune(bin); Bgetd(bin, &yylval.val); return NUMBER; } if(isalpharune(r)){ p = sname; do{ if(p+runelen(r) - sname >= sizeof(sname)) return r; /* force syntax error. */ p += runetochar(p, &r); }while((r = Bgetrune(bin)) != Beof && (isalpharune(r) || isdigitrune(r))); Bungetrune(bin); *p = 0; if((t = lookuptype(sname)) >= 0){ yylval.type = t; return TYPE; } if((s = lookup(sname)) == nil) s = install(sname, UNDEF, 0); yylval.sym = s; return s->type == UNDEF || s->type == CONST ? VAR : s->type; } if(r == '\n') lineno++; return r; } void usage(void) { fprint(2, "usage: %s\n", argv0); exits("usage"); } void main(int argc, char *argv[]) { ARGBEGIN{ default: usage(); }ARGEND; if(argc > 0) usage(); bin = Bfdopen(0, OREAD); if(bin == nil) sysfatal("Bfdopen: %r"); lineno++; init(); yyparse(); Bterm(bin); exits(nil); }