#include "yo.h" static Node* sourcefile(void); static Type* parameters(void); static Node* expr(void); static Node* exprlist(void); static Node* topdecl(void); static Node* decltype(void); static Node* declvar(void); static Type* type(void); static Node* primaryexprs(void); static void importdecl(void); static Node* litvalue(void); static Node* operand(void); static Node* stmtlist(void); Node* parse(char *name) { lexstart(name); want((int[]){Lpackage, 0}); Sym *s = want((int[]){Lid, 0}).sym; if(pkgname == nil) pkgname = s; assert(pkgname==nil || pkgname == s); importdecl(); Node *n = sourcefile(); return n; } Node** parsefiles(char **srcs, int n) { Node **arr = new(sizeof(Node*)*(n+1)); for(int i = 0; i < n; ++i){ arr[i] = parse(srcs[i]); } return arr; } static Sym* trygetpkg(Sym *s) { if(s->decl&&s->decl->ty&&s->decl->ty->kind == Tpkg){ if(try((int[]){'.',0}).kind != '.') return nil; Sym *ss = want((int[]){Lid,0}).sym; Decl *d = isinpkg(s->decl->ty->ids, ss); assert(d != nil); return d->sym; } return nil; } static Node* sconstval(void) { Token t = want((int[]){Lsconst,0}); return mksconst(t.sym); } static Node* constval(void) { Node *n; Token t = want((int[]){Lconst,0}); if(t.sym == truedecl->sym){ n = mkn(Oconst, nil, nil); n->ty = tbool; n->val = 1; }else if(t.sym == falsedecl->sym){ n = mkn(Oconst, nil, nil); n->ty = tbool; n->val = 0; }else n = mkconst(t.num); return n; } static Decl* ident(void) { Token t = want((int[]){Lid,0}); return mkids(t.sym, nil, nil); } // identlist = Lid {',' Lid} static Decl* identlist(void) { Decl h={0}, *p=&h; p = p->next = ident(); for(;try((int[]){',',0}).kind;){ p = p->next = ident(); } return h.next; } static Node* name(void) { Sym *s = want((int[]){Lid,0}).sym; Sym *p = trygetpkg(s); if(p){ Node *n = mkn(Opkg,nil,nil); n->decl = p->decl; n->ty = p->decl->ty; return n; } return mkname(s); } // argments = '(' exprlist ')' static Node* argments(void) { want((int[]){'(',0}); if(try((int[]){')',0}).kind) return nil; Node *n = exprlist(); if(n->op != Oseq) n = mkn(Oseq, n, nil); want((int[]){')',0}); return n; } static Node* compoundexpr(void) { Node *n; want((int[]){'(',0}); n = exprlist(); want((int[]){')',0}); assert(n->op == Oseq); return mkn(Otup, n, nil); } static Node* bltlen(void) { want((int[]){Llen,0}); want((int[]){'(',0}); Node *l = name(); want((int[]){')',0}); Node *n = mkn(Olen, l, nil); return n; } // ElementList = KeyedElement { "," KeyedElement } . // KeyedElement = [ Key ":" ] Element . // Key = FieldName | Expression | LiteralValue . // FieldName = identifier . // Element = Expression | LiteralValue . static Node* element(void) { if(peek((int[]){'{',0}).kind) return litvalue(); return expr(); } static Node* elemlist(void) { Node h={0}, *p=&h; p = p->r = mkn(Oseq, element(), nil); while(try((int[]){',',0}).kind) p = p->r = mkn(Oseq, element(), nil); return h.r; } // LiteralValue = "{" [ ElementList [ "," ] ] "}" . static Node* litvalue(void) { want((int[]){'{',0}); if(try((int[]){'}', 0}).kind) return nil; Node *n = elemlist(); want((int[]){'}',0}); return n; } static Node* compositelit(void) { Token t = want((int[]){Lid,0}); Node *n = litvalue(); n = mkn(Ostruct, n, nil); n->ty = mkidtype(t.sym); return n; } static int litlen(Node *n) { int i = 0; for(; n; n=n->r) ++i; return i; } static Node* arraylit(void) { Type *t = type(); Node *n = litvalue(); int l = litlen(n); if(t->len) assert(t->len >= l); else t->len = l; n = mkn(Oarray, n, nil); n->ty = t; return n; } static Node* operand(void) { Token t = peek((int[]){Lid,Lstruct,Lsconst,Lconst,Llen,'(','[',0}); switch(t.kind){ case '[': return arraylit(); case '(': return compoundexpr(); case Lstruct: return compositelit(); case Lid: return name(); case Lsconst: return sconstval(); case Lconst: return constval(); case Llen: return bltlen(); default: assert(0); } } static Node* index(Node *id) { Node *n=nil, *l=nil, *r=nil; want((int[]){'[',0}); switch(try((int[]){':',']',0}).kind){ case ']': assert(0); case ':': if(try((int[]){']',0}).kind) return mkn(Oslice, id, mkn(Oseq, nil, nil)); n = mkn(Oslice, id, mkn(Oseq, nil, expr())); break; default: l = expr(); if(peek((int[]){']',0}).kind){ n = mkn(Oindex, id, l); break; } want((int[]){':',0}); if(peek((int[]){']',0}).kind){ n = mkn(Oslice, id, mkn(Oseq, l, nil)); break; } r = expr(); n = mkn(Oslice, id, mkn(Oseq, l, r)); } want((int[]){']',0}); return n; } static Node* primaryexprs(void) { Node h={0}, *p=&h; p = operand(); for(;;){ switch(peek((int[]){'.','(','[',0}).kind){ case '.': lex(); p = mkn(Odot, p, operand()); break; case '(': p = mkn(Ocall, p, argments()); break; case '[': p = index(p); break; default: return p; } } } // unrayexpr = primaryexprs | unray-op unrayexpr static Node* unrayexpr(void) { switch(try((int[]){'+','-','*','/','&',0}).kind){ default: return primaryexprs(); case '+': case '-': case '!': case '/': case '^': assert(0); case '*': return mkn(Oxref, unrayexpr(), nil); case '&': return mkn(Oref,unrayexpr(), nil); } } // mul-op = ('*'|'/') primary static Node* mulop(void) { int c; Node *p = unrayexpr(); while((c = try((int[]){'*','/',0}).kind)) switch(c){ case '*': p = mkn(Omul, p, unrayexpr()); break; default: assert(0); } return p; } // add-op = [mul-op] ('+'|'-') expr static Node* addop(void) { int c; Node *p = mulop(); while((c = try((int[]){'+','-',0}).kind)) switch(c){ case '+': p = mkn(Oadd, p, mulop()); break; case '-': p = mkn(Osub, p, mulop()); break; default: assert(0); } return p; } static Node* relop(void) { int c, op; Node *p = addop(); while((c = try((int[]){Leq,Lneq,Lgeq,Lleq,'>','<',0}).kind)){ switch(c){ case '<': op = Olt; break; case '>': op = Ogt; break; case Leq: op = Oeq; break; case Lneq: op = Oneq; break; case Lgeq: op = Ogeq; break; case Lleq: op = Oleq; break; default: assert(0); } p = mkn(op, p, addop()); } return p; } static Node* expr(void) { return relop(); } // exprlist = expr {',' expr } static Node* exprlist(void) { Node h={0}, *p=&h; p->r = expr(); if(peek((int[]){',',0}).kind == 0) return p->r; p = p->r = mkn(Oseq, p->r, nil); for(;try((int[]){',',0}).kind;){ p = p->r = mkn(Oseq, expr(), nil); } return h.r; } // estmt = expr // SimpleStmt = Assignment Node* sstmt(void) { Node *r = nil; Node *l = exprlist(); switch(try((int[]){'=',Ldas,0}).kind){ case '=': r = exprlist(); return mkn(Oas, l, r); case Ldas: r = exprlist(); return mkn(Odas, l, r); default: return l; } } static Node* retstmt(void) { want((int[]){Lret,0}); if(peek((int[]){';',0}).kind) return mkn(Oret, nil, nil); Node *n = expr(); return mkn(Oret, n, nil); } // block = '{' stmtlist '}' static Node* block(void) { want((int[]){'{',0}); Node *n = stmtlist(); n = mkscope(n); want((int[]){'}',0}); return n; } static Node* ifstmt(void) { Node *n,*l,*p,*r, *c = nil; want((int[]){Lif,0}); l = sstmt(); if(try((int[]){';',0}).kind) c = expr(); p = mkunray(Oseq, block()); if(c) n = mkn(Oscope, l, mkn(Oif, c, p)); else n = mkn(Oif, l, p); for(c = nil; try((int[]){Lelse,0}).kind; c = nil){ if(try((int[]){Lif,0}).kind){ l = sstmt(); if(try((int[]){';',0}).kind) c = expr(); r = mkunray(Oseq, block()); if(c) p->r = mkn(Oscope, l, mkn(Oif, c, r)); else p->r = mkn(Oif, l, r); p = r; }else p->r = block(); } return n; } // for [ cond | forclause | rangeclause ] block // ForClause = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] . static Node * mkfor(Node *init, Node *cond, Node *post, Node *body) { Node *n; n = mkn(Oseq, body, post); n = mkn(Ofor, cond, n); if(init) return mkn(Oscope, init, n); return n; } static Node* forstmt(void) { Node *i=nil, *c=nil, *p=nil, *tmp=nil; want((int[]){Lfor,0}); if(peek((int[]){'{',0}).kind) return mkfor(i, mkbool(1), nil, block()); if(peek((int[]){';',0}).kind == 0) tmp = sstmt(); if(peek((int[]){'{',0}).kind){ assert((c = tmp) != nil); assert(c->op != Odas && c->op != Oas); return mkfor(nil, c, nil, block()); } want((int[]){';',0}); i = tmp; tmp = nil; if(try((int[]){';',0}).kind) c = mkbool(1); else if(peek((int[]){'{'}).kind) assert(0); else{ c = expr(); want((int[]){';',0}); } if(peek((int[]){'{'}).kind) return mkfor(i, c, nil, block()); p = sstmt(); assert(p->op != Odas); return mkfor(i, c, p, block()); } // stmt = simple-stmt | decl static Node* stmt(void) { switch(peek((int[]){Lret,Lif,Lfor,Ltype,Lvar,'{',0}).kind){ case Lret: return retstmt(); case Lfor: return forstmt(); case Lif: return ifstmt(); case Ltype: return decltype(); case Lvar: return declvar(); case '{': return block(); default: return sstmt(); } } static Node* stmtlist(void) { Node h={0}, *p=&h; for(;peek((int[]){'}',0}).kind==0;){ p = p->r = mkn(Oseq, stmt(), nil); want((int[]){';',0}); } return h.r; } // '{' stmtlist '}' static Node* fbody(void) { want((int[]){'{',0}); if((try((int[]){'}',0})).kind) return nil; Node *n = stmtlist(); want((int[]){'}',0}); return n; } // StructType = "struct" "{" { FieldDecl ";" } "}" . // FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] . // EmbeddedField = [ "*" ] TypeName [ TypeArgs ] . // Tag = string_lit . static Node* field(void) { Decl *ids = identlist(); Decl *t = typeids(ids, type()); want((int[]){';', 0}); return fielddecl(Dfield, t); } static Node* fields(void) { Node h={0}, *p=&h; for(;;) switch(peek((int[]){Lid,Ltid,0}).kind){ case Lid: case Ltid: p = p->r = mkn(Oseq, field(), nil); break; default: return h.r; } } // [identlist] Type static Decl* paramdecl(void) { Decl *ids = identlist(); Type *t = type(); return typeids(ids, t); } // paramdecl {"," paramdecl} static Decl* paramlist(void) { Decl h={0}, *p = &h; p = p->next = paramdecl(); for(;try((int[]){',',0}).kind==',';) p = p->next = paramdecl(); return h.next; } // "(" [parameterlist [ ',' ] ] ")" static Type* parameters(void) { Decl h={0}, *p=&h; want((int[]){'(',0}); for(;try((int[]){')',0}).kind==0;) p = p->next = paramlist(); return mktype(Tfn, 0, tnone, h.next); } static Type* arraytype(void) { Type *ty; Token t; want((int[]){'[',0}); switch((t = try((int[]){Lid,Lconst,0})).kind){ case Lid: assert(t.sym->decl == _decl); want((int[]){']',0}); ty = mktype(Tarray, 0, type(), nil); ty->len = 0; return ty; case Lconst: assert(t.num > 0); want((int[]){']',0}); ty = mktype(Tarray, 0, type(), nil); assert((ty->len = t.num) > 0); return ty; default : assert(0); } } static Type* type(void) { Type h = {0}, *p=&h; Sym *s; Token t = want((int[]){Lid,Ltid,'*','[',0}); switch(t.kind){ case '*': do{ p = p->tof = mktype(Tptr, IBY2WD, nil, nil); }while(try((int[]){'*',0}).kind); p->tof = type(); return h.tof; case Lid: case Ltid: if((s = trygetpkg(t.sym))) return s->decl->ty; else return mkidtype(t.sym); case '[': unlex(t); return arraytype(); default: assert(0); } } // type ["," type] static Decl* typelist(void) { Decl h={0}, *p=&h; p = p->next = mkids(nil, type(), nil); for(;try((int[]){',',0}).kind==',';) p = p->next = mkids(nil, type(), nil); return h.next; } static Type* tuptype(void) { want((int[]){'(',0}); Decl *d = typelist(); want((int[]){')',0}); assert(d->next != nil); return mktype(Ttup, 0, nil, d); } static Type* fnresult(void) { switch(peek((int[]){Lid, Ltid,'[','*','(',0}).kind){ case '[': case '*': case Lid: case Ltid: return type(); case '(': return tuptype(); default: return tnone; } } // parameters [result] static Type* signature(void) { Type *param = parameters(); param->tof = fnresult(); return param; } // funcdecl "fn" Lid signature fbody static Node* declfn(void) { want((int[]){Lfn,0}); Node *nm = name(); Type *s = signature(); Node *b = fbody(); Node *n = fndecl(nm, s, b); return n; } // var-spec = identlist (Type ['=' exprlist] | '=' exprlist ) // var-decl = Lvar varspec static Node* declvar(void) { want((int[]){Lvar,0}); Decl *d = identlist(); Type *t = type(); switch(peek((int[]){';','=',0}).kind){ case ';': return vardecl(d, t); default:assert(0); } } // type-decl = Ltype Lid (Lstruct) '{' fields '}' static Node* decltype(void) { want((int[]){Ltype,0}); Token t = want((int[]){Lid,0}); Decl *id = mkids(t.sym, 0, nil); want((int[]){Lstruct,0}); want((int[]){'{',0}); Node *f = fields(); want((int[]){'}',0}); return structdecl(id, f); } static Node* decl(void) { switch(peek((int[]){Ltype,Lvar,0}).kind){ case Ltype: return decltype(); case Lvar: return declvar(); default: assert(0); } } static Node* declexport(void) { Node *n; want((int[]){Lexport,0}); switch(peek((int[]){Lfn,Lvar,Ltype,0}).kind){ case Lfn: n=declfn(); break; case Ltype: n=decltype(); break; case Lvar: n=declvar(); break; default: assert(0); } return mkn(Oexport, n, nil); } static Node* topdecl(void) { switch(peek((int[]){Lexport,Lfn,0}).kind){ case Lexport: return declexport(); case Lfn: return declfn(); default: return decl(); } } // SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } . static Node* sourcefile(void) { Node h={0}, *p = &h; for(;;){ switch(peek((int[]){EOF,0}).kind){ case EOF: return h.r; default: p=p->r=mkn(Oseq, topdecl(), nil); want((int[]){';',0}); break; } } return h.r; } static Type* imtype(void) { Type *t = mkidtype(dotsym()); t->kind = want((int[]){Lconst,0}).num; t->size = want((int[]){Lconst,0}).num; t->offset = want((int[]){Lconst,0}).num; return t; } static Type* imparam(int n) { if(n == 0) return nil; Type *res = mktype(Tpfn, 0, nil, nil); res->size = want((int[]){Lconst,0}).num; Decl h, *p=&h; for(int i = 0; i < n; i++){ Type *t = imtype(); Decl *d = mkids(nil, t, nil); d->offset = t->offset; p = p->next = d; } res->ids = h.next; return res; } static Type* imret(int n) { if(n == 0) return tnone; if(n == 1){ want((int[]){Lconst,0}); want((int[]){Lconst,0}); return imtype(); } Type *res = mktype(Ttup, 0, nil, nil); res->size = want((int[]){Lconst,0}).num; res->offset = want((int[]){Lconst,0}).num; Decl h, *p = &h; for(int i = 0; i < n; i++){ p = p->next = mkids(nil, imtype(), nil); } res->ids = h.next; return res; } static Decl* imdeclfn(void) { want((int[]){Lfn,0}); Sym *s = dotsym(); int sz = want((int[]){Lconst,0}).num; int pc = want((int[]){Lconst,0}).num; int args = want((int[]){Lconst,0}).num; int rets = want((int[]){Lconst,0}).num; Type *t = imparam(args); t->tof = imret(rets); Decl *d = mkids(s, t, nil); d->pc = new(sizeof(Inst)); d->store = Dpkg; d->offset = sz; d->pc->pc = pc; d->pc->m.reg = nimport; s->decl = d; return d; } static Decl* imstruct(void) { want((int[]){Ltype,0}); Sym *s = dotsym(); want((int[]){Lstruct,0}); Type *t = mktype(Tstruct, 0, nil, nil); t->size = want((int[]){Lconst,0}).num; int n = want((int[]){Lconst,0}).num; Decl *res = mkids(s, t, nil); res->store = Dtype; Decl h={0}, *p=&h; for(int i = 0; i < n; ++i){ Decl *c = ident(); c->ty = imtype(); c->dot = res; c->store = Dfield; p = p->next = c; } t->ids = h.next; t->decl = res; s->decl = res; return res; } static Decl* imfields(Import *i) { Decl h, *p=&h, *t; for(;;){ switch(peek((int[]){Lfn,Ltype,Leof,0}).kind){ default : assert(0); case Leof: return h.next; case Ltype: t = imstruct(); break; case Lfn: t = imdeclfn(); break; } p = p->next = t; } } static void entryimport(Import *i, Sym *path) { i->path = path; Decl *id = ident(); i->sym = id->sym; i->decls = imfields(i); Type *ty = mktype(Tpkg, 0, nil, i->decls); id->ty = ty; for(Decl *p=ty->ids; p; p=p->next) p->dot = id; installids(Dpkg, id); } static void importdecl(void) { for(;try((int[]){Limport,0}).kind;){ Sym *path = want((int[]){Lsconst, 0}).sym; if(isimported(path)) return; imports = realloc(imports, (nimport+1)*sizeof(Import)); importdef(path); entryimport(&imports[nimport], path); nimport += 1; } }