summaryrefslogtreecommitdiff
path: root/limbo/limbo.y
diff options
context:
space:
mode:
Diffstat (limited to 'limbo/limbo.y')
-rw-r--r--limbo/limbo.y2032
1 files changed, 2032 insertions, 0 deletions
diff --git a/limbo/limbo.y b/limbo/limbo.y
new file mode 100644
index 00000000..7098cd5d
--- /dev/null
+++ b/limbo/limbo.y
@@ -0,0 +1,2032 @@
+%{
+#include "limbo.h"
+%}
+
+%union
+{
+ struct{
+ Src src;
+ union{
+ Sym *idval;
+ Long ival;
+ Real rval;
+ }v;
+ }tok;
+ Decl *ids;
+ Node *node;
+ Type *type;
+ Typelist *types;
+}
+
+%type <type> type fnarg fnargret fnargretp adtk fixtype iditype dotiditype
+%type <ids> ids rids nids nrids tuplist forms ftypes ftype
+ bclab bctarg ptags rptags polydec
+%type <node> zexp exp monexp term elist zelist celist
+ idatom idterms idterm idlist
+ initlist elemlist elem qual
+ decl topdecls topdecl fndef fbody stmt stmts qstmts qbodies cqstmts cqbodies
+ mdecl adtdecl mfield mfields field fields fnname
+ pstmts pbodies pqual pfields pfbody pdecl dfield dfields
+ eqstmts eqbodies idexc edecl raises tpoly tpolys texp export exportlist forpoly
+%type <types> types
+
+%right <tok.src> '=' Landeq Loreq Lxoreq Llsheq Lrsheq
+ Laddeq Lsubeq Lmuleq Ldiveq Lmodeq Lexpeq Ldeclas
+%left <tok.src> Lload
+%left <tok.src> Loror
+%left <tok.src> Landand
+%right <tok.src> Lcons
+%left <tok.src> '|'
+%left <tok.src> '^'
+%left <tok.src> '&'
+%left <tok.src> Leq Lneq
+%left <tok.src> '<' '>' Lleq Lgeq
+%left <tok.src> Llsh Lrsh
+%left <tok.src> '+' '-'
+%left <tok.src> '*' '/' '%'
+%right <tok.src> Lexp
+%right <tok.src> Lcomm
+
+%left <tok.src> '(' ')' '[' ']' Linc Ldec Lof Lref
+%right <tok.src> Lif Lelse Lfn ':' Lexcept Lraises
+%left <tok.src> Lmdot
+%left <tok.src> '.'
+
+%left <tok.src> Lto
+%left <tok.src> Lor
+
+
+%nonassoc <tok.v.rval> Lrconst
+%nonassoc <tok.v.ival> Lconst
+%nonassoc <tok.v.idval> Lid Ltid Lsconst
+%nonassoc <tok.src> Llabs Lnil
+ '!' '~' Llen Lhd Ltl Ltagof
+ '{' '}' ';'
+ Limplement Limport Linclude
+ Lcon Ltype Lmodule Lcyclic
+ Ladt Larray Llist Lchan Lself
+ Ldo Lwhile Lfor Lbreak
+ Lalt Lcase Lpick Lcont
+ Lreturn Lexit Lspawn Lraise Lfix
+%%
+prog : Limplement ids ';'
+ {
+ impmods = $2;
+ } topdecls
+ {
+ tree = rotater($5);
+ }
+ | topdecls
+ {
+ impmods = nil;
+ tree = rotater($1);
+ }
+ ;
+
+topdecls: topdecl
+ | topdecls topdecl
+ {
+ if($1 == nil)
+ $$ = $2;
+ else if($2 == nil)
+ $$ = $1;
+ else
+ $$ = mkbin(Oseq, $1, $2);
+ }
+ ;
+
+topdecl : error ';'
+ {
+ $$ = nil;
+ }
+ | decl
+ | fndef
+ | adtdecl ';'
+ | mdecl ';'
+ | idatom '=' exp ';'
+ {
+ $$ = mkbin(Oas, $1, $3);
+ }
+ | idterm '=' exp ';'
+ {
+ $$ = mkbin(Oas, $1, $3);
+ }
+ | idatom Ldeclas exp ';'
+ {
+ $$ = mkbin(Odas, $1, $3);
+ }
+ | idterm Ldeclas exp ';'
+ {
+ $$ = mkbin(Odas, $1, $3);
+ }
+ | idterms ':' type ';'
+ {
+ yyerror("illegal declaration");
+ $$ = nil;
+ }
+ | idterms ':' type '=' exp ';'
+ {
+ yyerror("illegal declaration");
+ $$ = nil;
+ }
+ ;
+
+idterms : idterm
+ | idterms ',' idterm
+ {
+ $$ = mkbin(Oseq, $1, $3);
+ }
+ ;
+
+decl : Linclude Lsconst ';'
+ {
+ includef($2);
+ $$ = nil;
+ }
+ | ids ':' Ltype type ';'
+ {
+ $$ = typedecl($1, $4);
+ }
+ | ids ':' Limport exp ';'
+ {
+ $$ = importdecl($4, $1);
+ $$->src.start = $1->src.start;
+ $$->src.stop = $5.stop;
+ }
+ | ids ':' type ';'
+ {
+ $$ = vardecl($1, $3);
+ }
+ | ids ':' type '=' exp ';'
+ {
+ $$ = mkbin(Ovardecli, vardecl($1, $3), varinit($1, $5));
+ }
+ | ids ':' Lcon exp ';'
+ {
+ $$ = condecl($1, $4);
+ }
+ | edecl
+ ;
+
+edecl : ids ':' Lexcept ';'
+ {
+ $$ = exdecl($1, nil);
+ }
+ | ids ':' Lexcept '(' tuplist ')' ';'
+ {
+ $$ = exdecl($1, revids($5));
+ }
+ ;
+
+mdecl : ids ':' Lmodule '{' mfields '}'
+ {
+ $1->src.stop = $6.stop;
+ $$ = moddecl($1, rotater($5));
+ }
+ ;
+
+mfields :
+ {
+ $$ = nil;
+ }
+ | mfields mfield
+ {
+ if($1 == nil)
+ $$ = $2;
+ else if($2 == nil)
+ $$ = $1;
+ else
+ $$ = mkn(Oseq, $1, $2);
+ }
+ | error
+ {
+ $$ = nil;
+ }
+ ;
+
+mfield : ids ':' type ';'
+ {
+ $$ = fielddecl(Dglobal, typeids($1, $3));
+ }
+ | adtdecl ';'
+ | ids ':' Ltype type ';'
+ {
+ $$ = typedecl($1, $4);
+ }
+ | ids ':' Lcon exp ';'
+ {
+ $$ = condecl($1, $4);
+ }
+ | edecl
+ ;
+
+adtdecl : ids ':' Ladt polydec '{' fields '}' forpoly
+ {
+ $1->src.stop = $7.stop;
+ $$ = adtdecl($1, rotater($6));
+ $$->ty->polys = $4;
+ $$->ty->val = rotater($8);
+ }
+ | ids ':' Ladt polydec Lfor '{' tpolys '}' '{' fields '}'
+ {
+ $1->src.stop = $11.stop;
+ $$ = adtdecl($1, rotater($10));
+ $$->ty->polys = $4;
+ $$->ty->val = rotater($7);
+ }
+ ;
+
+forpoly :
+ {
+ $$ = nil;
+ }
+ | Lfor '{' tpolys '}'
+ {
+ $$ = $3;
+ }
+ ;
+
+fields :
+ {
+ $$ = nil;
+ }
+ | fields field
+ {
+ if($1 == nil)
+ $$ = $2;
+ else if($2 == nil)
+ $$ = $1;
+ else
+ $$ = mkn(Oseq, $1, $2);
+ }
+ | error
+ {
+ $$ = nil;
+ }
+ ;
+
+field : dfield
+ | pdecl
+ | ids ':' Lcon exp ';'
+ {
+ $$ = condecl($1, $4);
+ }
+ ;
+
+dfields :
+ {
+ $$ = nil;
+ }
+ | dfields dfield
+ {
+ if($1 == nil)
+ $$ = $2;
+ else if($2 == nil)
+ $$ = $1;
+ else
+ $$ = mkn(Oseq, $1, $2);
+ }
+ ;
+
+dfield : ids ':' Lcyclic type ';'
+ {
+ Decl *d;
+
+ for(d = $1; d != nil; d = d->next)
+ d->cyc = 1;
+ $$ = fielddecl(Dfield, typeids($1, $4));
+ }
+ | ids ':' type ';'
+ {
+ $$ = fielddecl(Dfield, typeids($1, $3));
+ }
+ ;
+
+pdecl : Lpick '{' pfields '}'
+ {
+ $$ = $3;
+ }
+ ;
+
+pfields : pfbody dfields
+ {
+ $1->right->right = $2;
+ $$ = $1;
+ }
+ | pfbody error
+ {
+ $$ = nil;
+ }
+ | error
+ {
+ $$ = nil;
+ }
+ ;
+
+pfbody : ptags Llabs
+ {
+ $$ = mkn(Opickdecl, nil, mkn(Oseq, fielddecl(Dtag, $1), nil));
+ typeids($1, mktype(&$1->src.start, &$1->src.stop, Tadtpick, nil, nil));
+ }
+ | pfbody dfields ptags Llabs
+ {
+ $1->right->right = $2;
+ $$ = mkn(Opickdecl, $1, mkn(Oseq, fielddecl(Dtag, $3), nil));
+ typeids($3, mktype(&$3->src.start, &$3->src.stop, Tadtpick, nil, nil));
+ }
+ | pfbody error ptags Llabs
+ {
+ $$ = mkn(Opickdecl, nil, mkn(Oseq, fielddecl(Dtag, $3), nil));
+ typeids($3, mktype(&$3->src.start, &$3->src.stop, Tadtpick, nil, nil));
+ }
+ ;
+
+ptags : rptags
+ {
+ $$ = revids($1);
+ }
+ ;
+
+rptags : Lid
+ {
+ $$ = mkids(&$<tok.src>1, $1, nil, nil);
+ }
+ | rptags Lor Lid
+ {
+ $$ = mkids(&$<tok.src>3, $3, nil, $1);
+ }
+ ;
+
+ids : rids
+ {
+ $$ = revids($1);
+ }
+ ;
+
+rids : Lid
+ {
+ $$ = mkids(&$<tok.src>1, $1, nil, nil);
+ }
+ | rids ',' Lid
+ {
+ $$ = mkids(&$<tok.src>3, $3, nil, $1);
+ }
+ ;
+
+fixtype : Lfix '(' exp ',' exp ')'
+ {
+ $$ = mktype(&$1.start, &$6.stop, Tfix, nil, nil);
+ $$->val = mkbin(Oseq, $3, $5);
+ }
+ | Lfix '(' exp ')'
+ {
+ $$ = mktype(&$1.start, &$4.stop, Tfix, nil, nil);
+ $$->val = $3;
+ }
+ ;
+
+types : type
+ {
+ $$ = addtype($1, nil);
+ }
+ | Lcyclic type
+ {
+ $$ = addtype($2, nil);
+ $2->flags |= CYCLIC;
+ }
+ | types ',' type
+ {
+ $$ = addtype($3, $1);
+ }
+ | types ',' Lcyclic type
+ {
+ $$ = addtype($4, $1);
+ $4->flags |= CYCLIC;
+ }
+ ;
+
+type : Ltid
+ {
+ $$ = mkidtype(&$<tok.src>1, $1);
+ }
+ | iditype
+ {
+ $$ = $1;
+ }
+ | dotiditype
+ {
+ $$ = $1;
+ }
+ | type Lmdot Lid
+ {
+ $$ = mkarrowtype(&$1->src.start, &$<tok.src>3.stop, $1, $3);
+ }
+ | type Lmdot Lid '[' types ']'
+ {
+ $$ = mkarrowtype(&$1->src.start, &$<tok.src>3.stop, $1, $3);
+ $$ = mkinsttype(&$1->src, $$, $5);
+ }
+ | Lref type
+ {
+ $$ = mktype(&$1.start, &$2->src.stop, Tref, $2, nil);
+ }
+ | Lchan Lof type
+ {
+ $$ = mktype(&$1.start, &$3->src.stop, Tchan, $3, nil);
+ }
+ | '(' tuplist ')'
+ {
+ if($2->next == nil)
+ $$ = $2->ty;
+ else
+ $$ = mktype(&$1.start, &$3.stop, Ttuple, nil, revids($2));
+ }
+ | Larray Lof type
+ {
+ $$ = mktype(&$1.start, &$3->src.stop, Tarray, $3, nil);
+ }
+ | Llist Lof type
+ {
+ $$ = mktype(&$1.start, &$3->src.stop, Tlist, $3, nil);
+ }
+ | Lfn polydec fnargretp raises
+ {
+ $3->src.start = $1.start;
+ $3->polys = $2;
+ $3->u.eraises = $4;
+ $$ = $3;
+ }
+ | fixtype
+/*
+ | Lexcept
+ {
+ $$ = mktype(&$1.start, &$1.stop, Texception, nil, nil);
+ $$->cons = 1;
+ }
+ | Lexcept '(' tuplist ')'
+ {
+ $$ = mktype(&$1.start, &$4.stop, Texception, nil, revids($3));
+ $$->cons = 1;
+ }
+*/
+ ;
+
+iditype : Lid
+ {
+ $$ = mkidtype(&$<tok.src>1, $1);
+ }
+ | Lid '[' types ']'
+ {
+ $$ = mkinsttype(&$<tok.src>1, mkidtype(&$<tok.src>1, $1), $3);
+ }
+ ;
+
+dotiditype : type '.' Lid
+ {
+ $$ = mkdottype(&$1->src.start, &$<tok.src>3.stop, $1, $3);
+ }
+ | type '.' Lid '[' types ']'
+ {
+ $$ = mkdottype(&$1->src.start, &$<tok.src>3.stop, $1, $3);
+ $$ = mkinsttype(&$1->src, $$, $5);
+ }
+ ;
+
+tuplist : type
+ {
+ $$ = mkids(&$1->src, nil, $1, nil);
+ }
+ | tuplist ',' type
+ {
+ $$ = mkids(&$1->src, nil, $3, $1);
+ }
+ ;
+
+polydec :
+ {
+ $$ = nil;
+ }
+ | '[' ids ']'
+ {
+ $$ = polydecl($2);
+ }
+ ;
+
+fnarg : '(' forms ')'
+ {
+ $$ = mktype(&$1.start, &$3.stop, Tfn, tnone, $2);
+ }
+ | '(' '*' ')'
+ {
+ $$ = mktype(&$1.start, &$3.stop, Tfn, tnone, nil);
+ $$->varargs = 1;
+ }
+ | '(' ftypes ',' '*' ')'
+ {
+ $$ = mktype(&$1.start, &$5.stop, Tfn, tnone, $2);
+ $$->varargs = 1;
+ }
+ ;
+
+fnargret: fnarg %prec ':'
+ {
+ $$ = $1;
+ }
+ | fnarg ':' type
+ {
+ $1->tof = $3;
+ $1->src.stop = $3->src.stop;
+ $$ = $1;
+ }
+ ;
+
+fnargretp: fnargret %prec '='
+ {
+ $$ = $1;
+ }
+ | fnargret Lfor '{' tpolys '}'
+ {
+ $$ = $1;
+ $$->val = rotater($4);
+ }
+ ;
+
+forms :
+ {
+ $$ = nil;
+ }
+ | ftypes
+ ;
+
+ftypes : ftype
+ | ftypes ',' ftype
+ {
+ $$ = appdecls($1, $3);
+ }
+ ;
+
+ftype : nids ':' type
+ {
+ $$ = typeids($1, $3);
+ }
+ | nids ':' adtk
+ {
+ Decl *d;
+
+ $$ = typeids($1, $3);
+ for(d = $$; d != nil; d = d->next)
+ d->implicit = 1;
+ }
+ | idterms ':' type
+ {
+ $$ = mkids(&$1->src, enter("junk", 0), $3, nil);
+ $$->store = Darg;
+ yyerror("illegal argument declaraion");
+ }
+ | idterms ':' adtk
+ {
+ $$ = mkids(&$1->src, enter("junk", 0), $3, nil);
+ $$->store = Darg;
+ yyerror("illegal argument declaraion");
+ }
+ ;
+
+nids : nrids
+ {
+ $$ = revids($1);
+ }
+ ;
+
+nrids : Lid
+ {
+ $$ = mkids(&$<tok.src>1, $1, nil, nil);
+ $$->store = Darg;
+ }
+ | Lnil
+ {
+ $$ = mkids(&$1, nil, nil, nil);
+ $$->store = Darg;
+ }
+ | nrids ',' Lid
+ {
+ $$ = mkids(&$<tok.src>3, $3, nil, $1);
+ $$->store = Darg;
+ }
+ | nrids ',' Lnil
+ {
+ $$ = mkids(&$3, nil, nil, $1);
+ $$->store = Darg;
+ }
+ ;
+
+/*
+adttype : Lid
+ {
+ $$ = mkidtype(&$<tok.src>1, $1);
+ }
+ | adttype '.' Lid
+ {
+ $$ = mkdottype(&$1->src.start, &$<tok.src>3.stop, $1, $3);
+ }
+ | adttype Lmdot Lid
+ {
+ $$ = mkarrowtype(&$1->src.start, &$<tok.src>3.stop, $1, $3);
+ }
+ | Lref adttype
+ {
+ $$ = mktype(&$1.start, &$2->src.stop, Tref, $2, nil);
+ }
+ ;
+
+adtk : Lself adttype
+ {
+ $$ = $2;
+ }
+ ;
+*/
+
+adtk : Lself iditype
+ {
+ $$ = $2;
+ }
+ | Lself Lref iditype
+ {
+ $$ = mktype(&$<tok.src>2.start, &$<tok.src>3.stop, Tref, $3, nil);
+ }
+ | Lself dotiditype
+ {
+ $$ = $2;
+ }
+ | Lself Lref dotiditype
+ {
+ $$ = mktype(&$<tok.src>2.start, &$<tok.src>3.stop, Tref, $3, nil);
+ }
+ ;
+
+fndef : fnname fnargretp raises fbody
+ {
+ $$ = fndecl($1, $2, $4);
+ nfns++;
+ /* patch up polydecs */
+ if($1->op == Odot){
+ if($1->right->left != nil){
+ $2->polys = $1->right->left->decl;
+ $1->right->left = nil;
+ }
+ if($1->left->op == Oname && $1->left->left != nil){
+ $$->decl = $1->left->left->decl;
+ $1->left->left = nil;
+ }
+ }
+ else{
+ if($1->left != nil){
+ $2->polys = $1->left->decl;
+ $1->left = nil;
+ }
+ }
+ $2->u.eraises = $3;
+ $$->src = $1->src;
+ }
+ ;
+
+raises : Lraises '(' idlist ')'
+ {
+ $$ = mkn(Otuple, rotater($3), nil);
+ $$->src.start = $1.start;
+ $$->src.stop = $4.stop;
+ }
+ | Lraises idatom
+ {
+ $$ = mkn(Otuple, mkunary(Oseq, $2), nil);
+ $$->src.start = $1.start;
+ $$->src.stop = $2->src.stop;
+ }
+ | /* empty */ %prec Lraises
+ {
+ $$ = nil;
+ }
+ ;
+
+fbody : '{' stmts '}'
+ {
+ if($2 == nil){
+ $2 = mkn(Onothing, nil, nil);
+ $2->src.start = curline();
+ $2->src.stop = $2->src.start;
+ }
+ $$ = rotater($2);
+ $$->src.start = $1.start;
+ $$->src.stop = $3.stop;
+ }
+ | error '}'
+ {
+ $$ = mkn(Onothing, nil, nil);
+ }
+ | error '{' stmts '}'
+ {
+ $$ = mkn(Onothing, nil, nil);
+ }
+ ;
+
+fnname : Lid polydec
+ {
+ $$ = mkname(&$<tok.src>1, $1);
+ if($2 != nil){
+ $$->left = mkn(Onothing, nil ,nil);
+ $$->left->decl = $2;
+ }
+ }
+ | fnname '.' Lid polydec
+ {
+ $$ = mkbin(Odot, $1, mkname(&$<tok.src>3, $3));
+ if($4 != nil){
+ $$->right->left = mkn(Onothing, nil ,nil);
+ $$->right->left->decl = $4;
+ }
+ }
+ ;
+
+stmts :
+ {
+ $$ = nil;
+ }
+ | stmts decl
+ {
+ if($1 == nil)
+ $$ = $2;
+ else if($2 == nil)
+ $$ = $1;
+ else
+ $$ = mkbin(Oseq, $1, $2);
+ }
+ | stmts stmt
+ {
+ if($1 == nil)
+ $$ = $2;
+ else
+ $$ = mkbin(Oseq, $1, $2);
+ }
+ ;
+
+elists : '(' elist ')'
+ | elists ',' '(' elist ')'
+ ;
+
+stmt : error ';'
+ {
+ $$ = mkn(Onothing, nil, nil);
+ $$->src.start = curline();
+ $$->src.stop = $$->src.start;
+ }
+ | error '}'
+ {
+ $$ = mkn(Onothing, nil, nil);
+ $$->src.start = curline();
+ $$->src.stop = $$->src.start;
+ }
+ | error '{' stmts '}'
+ {
+ $$ = mkn(Onothing, nil, nil);
+ $$->src.start = curline();
+ $$->src.stop = $$->src.start;
+ }
+ | '{' stmts '}'
+ {
+ if($2 == nil){
+ $2 = mkn(Onothing, nil, nil);
+ $2->src.start = curline();
+ $2->src.stop = $2->src.start;
+ }
+ $$ = mkscope(rotater($2));
+ }
+ | elists ':' type ';'
+ {
+ yyerror("illegal declaration");
+ $$ = mkn(Onothing, nil, nil);
+ $$->src.start = curline();
+ $$->src.stop = $$->src.start;
+ }
+ | elists ':' type '=' exp';'
+ {
+ yyerror("illegal declaration");
+ $$ = mkn(Onothing, nil, nil);
+ $$->src.start = curline();
+ $$->src.stop = $$->src.start;
+ }
+ | zexp ';'
+ {
+ $$ = $1;
+ }
+ | Lif '(' exp ')' stmt
+ {
+ $$ = mkn(Oif, $3, mkunary(Oseq, $5));
+ $$->src.start = $1.start;
+ $$->src.stop = $5->src.stop;
+ }
+ | Lif '(' exp ')' stmt Lelse stmt
+ {
+ $$ = mkn(Oif, $3, mkbin(Oseq, $5, $7));
+ $$->src.start = $1.start;
+ $$->src.stop = $7->src.stop;
+ }
+ | bclab Lfor '(' zexp ';' zexp ';' zexp ')' stmt
+ {
+ $$ = mkunary(Oseq, $10);
+ if($8->op != Onothing)
+ $$->right = $8;
+ $$ = mkbin(Ofor, $6, $$);
+ $$->decl = $1;
+ if($4->op != Onothing)
+ $$ = mkbin(Oseq, $4, $$);
+ }
+ | bclab Lwhile '(' zexp ')' stmt
+ {
+ $$ = mkn(Ofor, $4, mkunary(Oseq, $6));
+ $$->src.start = $2.start;
+ $$->src.stop = $6->src.stop;
+ $$->decl = $1;
+ }
+ | bclab Ldo stmt Lwhile '(' zexp ')' ';'
+ {
+ $$ = mkn(Odo, $6, $3);
+ $$->src.start = $2.start;
+ $$->src.stop = $7.stop;
+ $$->decl = $1;
+ }
+ | Lbreak bctarg ';'
+ {
+ $$ = mkn(Obreak, nil, nil);
+ $$->decl = $2;
+ $$->src = $1;
+ }
+ | Lcont bctarg ';'
+ {
+ $$ = mkn(Ocont, nil, nil);
+ $$->decl = $2;
+ $$->src = $1;
+ }
+ | Lreturn zexp ';'
+ {
+ $$ = mkn(Oret, $2, nil);
+ $$->src = $1;
+ if($2->op == Onothing)
+ $$->left = nil;
+ else
+ $$->src.stop = $2->src.stop;
+ }
+ | Lspawn exp ';'
+ {
+ $$ = mkn(Ospawn, $2, nil);
+ $$->src.start = $1.start;
+ $$->src.stop = $2->src.stop;
+ }
+ | Lraise zexp ';'
+ {
+ $$ = mkn(Oraise, $2, nil);
+ $$->src.start = $1.start;
+ $$->src.stop = $2->src.stop;
+ }
+ | bclab Lcase exp '{' cqstmts '}'
+ {
+ $$ = mkn(Ocase, $3, caselist($5, nil));
+ $$->src = $3->src;
+ $$->decl = $1;
+ }
+ | bclab Lalt '{' qstmts '}'
+ {
+ $$ = mkn(Oalt, caselist($4, nil), nil);
+ $$->src = $2;
+ $$->decl = $1;
+ }
+ | bclab Lpick Lid Ldeclas exp '{' pstmts '}'
+ {
+ $$ = mkn(Opick, mkbin(Odas, mkname(&$<tok.src>3, $3), $5), caselist($7, nil));
+ $$->src.start = $<tok.src>3.start;
+ $$->src.stop = $5->src.stop;
+ $$->decl = $1;
+ }
+ | Lexit ';'
+ {
+ $$ = mkn(Oexit, nil, nil);
+ $$->src = $1;
+ }
+ | '{' stmts '}' Lexcept idexc '{' eqstmts '}'
+ {
+ if($2 == nil){
+ $2 = mkn(Onothing, nil, nil);
+ $2->src.start = curline();
+ $2->src.stop = curline();
+ }
+ $2 = mkscope(rotater($2));
+ $$ = mkbin(Oexstmt, $2, mkn(Oexcept, $5, caselist($7, nil)));
+ }
+/*
+ | stmt Lexcept idexc '{' eqstmts '}'
+ {
+ $$ = mkbin(Oexstmt, $1, mkn(Oexcept, $3, caselist($5, nil)));
+ }
+*/
+ ;
+
+bclab :
+ {
+ $$ = nil;
+ }
+ | ids ':'
+ {
+ if($1->next != nil)
+ yyerror("only one identifier allowed in a label");
+ $$ = $1;
+ }
+ ;
+
+bctarg :
+ {
+ $$ = nil;
+ }
+ | Lid
+ {
+ $$ = mkids(&$<tok.src>1, $1, nil, nil);
+ }
+ ;
+
+qstmts : qbodies stmts
+ {
+ $1->left->right->right = $2;
+ $$ = $1;
+ }
+ ;
+
+qbodies : qual Llabs
+ {
+ $$ = mkunary(Oseq, mkscope(mkunary(Olabel, rotater($1))));
+ }
+ | qbodies stmts qual Llabs
+ {
+ $1->left->right->right = $2;
+ $$ = mkbin(Oseq, mkscope(mkunary(Olabel, rotater($3))), $1);
+ }
+ ;
+
+cqstmts : cqbodies stmts
+ {
+ $1->left->right = mkscope($2);
+ $$ = $1;
+ }
+ ;
+
+cqbodies : qual Llabs
+ {
+ $$ = mkunary(Oseq, mkunary(Olabel, rotater($1)));
+ }
+ | cqbodies stmts qual Llabs
+ {
+ $1->left->right = mkscope($2);
+ $$ = mkbin(Oseq, mkunary(Olabel, rotater($3)), $1);
+ }
+ ;
+
+eqstmts : eqbodies stmts
+ {
+ $1->left->right = mkscope($2);
+ $$ = $1;
+ }
+ ;
+
+eqbodies : qual Llabs
+ {
+ $$ = mkunary(Oseq, mkunary(Olabel, rotater($1)));
+ }
+ | eqbodies stmts qual Llabs
+ {
+ $1->left->right = mkscope($2);
+ $$ = mkbin(Oseq, mkunary(Olabel, rotater($3)), $1);
+ }
+ ;
+
+qual : exp
+ | exp Lto exp
+ {
+ $$ = mkbin(Orange, $1, $3);
+ }
+ | '*'
+ {
+ $$ = mkn(Owild, nil, nil);
+ $$->src = $1;
+ }
+ | qual Lor qual
+ {
+ $$ = mkbin(Oseq, $1, $3);
+ }
+ | error
+ {
+ $$ = mkn(Onothing, nil, nil);
+ $$->src.start = curline();
+ $$->src.stop = $$->src.start;
+ }
+ ;
+
+pstmts : pbodies stmts
+ {
+ $1->left->right = mkscope($2);
+ $$ = $1;
+ }
+ ;
+
+pbodies : pqual Llabs
+ {
+ $$ = mkunary(Oseq, mkunary(Olabel, rotater($1)));
+ }
+ | pbodies stmts pqual Llabs
+ {
+ $1->left->right = mkscope($2);
+ $$ = mkbin(Oseq, mkunary(Olabel, rotater($3)), $1);
+ }
+ ;
+
+pqual : Lid
+ {
+ $$ = mkname(&$<tok>1.src, $1);
+ }
+ | '*'
+ {
+ $$ = mkn(Owild, nil, nil);
+ $$->src = $1;
+ }
+ | pqual Lor pqual
+ {
+ $$ = mkbin(Oseq, $1, $3);
+ }
+ | error
+ {
+ $$ = mkn(Onothing, nil, nil);
+ $$->src.start = curline();
+ $$->src.stop = $$->src.start;
+ }
+ ;
+
+zexp :
+ {
+ $$ = mkn(Onothing, nil, nil);
+ $$->src.start = curline();
+ $$->src.stop = $$->src.start;
+ }
+ | exp
+ ;
+
+exp : monexp
+ | exp '=' exp
+ {
+ $$ = mkbin(Oas, $1, $3);
+ }
+ | exp Landeq exp
+ {
+ $$ = mkbin(Oandas, $1, $3);
+ }
+ | exp Loreq exp
+ {
+ $$ = mkbin(Ooras, $1, $3);
+ }
+ | exp Lxoreq exp
+ {
+ $$ = mkbin(Oxoras, $1, $3);
+ }
+ | exp Llsheq exp
+ {
+ $$ = mkbin(Olshas, $1, $3);
+ }
+ | exp Lrsheq exp
+ {
+ $$ = mkbin(Orshas, $1, $3);
+ }
+ | exp Laddeq exp
+ {
+ $$ = mkbin(Oaddas, $1, $3);
+ }
+ | exp Lsubeq exp
+ {
+ $$ = mkbin(Osubas, $1, $3);
+ }
+ | exp Lmuleq exp
+ {
+ $$ = mkbin(Omulas, $1, $3);
+ }
+ | exp Ldiveq exp
+ {
+ $$ = mkbin(Odivas, $1, $3);
+ }
+ | exp Lmodeq exp
+ {
+ $$ = mkbin(Omodas, $1, $3);
+ }
+ | exp Lexpeq exp
+ {
+ $$ = mkbin(Oexpas, $1, $3);
+ }
+ | exp Lcomm '=' exp
+ {
+ $$ = mkbin(Osnd, $1, $4);
+ }
+ | exp Ldeclas exp
+ {
+ $$ = mkbin(Odas, $1, $3);
+ }
+ | Lload Lid exp %prec Lload
+ {
+ $$ = mkn(Oload, $3, nil);
+ $$->src.start = $<tok.src.start>1;
+ $$->src.stop = $3->src.stop;
+ $$->ty = mkidtype(&$<tok.src>2, $2);
+ }
+ | exp Lexp exp
+ {
+ $$ = mkbin(Oexp, $1, $3);
+ }
+ | exp '*' exp
+ {
+ $$ = mkbin(Omul, $1, $3);
+ }
+ | exp '/' exp
+ {
+ $$ = mkbin(Odiv, $1, $3);
+ }
+ | exp '%' exp
+ {
+ $$ = mkbin(Omod, $1, $3);
+ }
+ | exp '+' exp
+ {
+ $$ = mkbin(Oadd, $1, $3);
+ }
+ | exp '-' exp
+ {
+ $$ = mkbin(Osub, $1, $3);
+ }
+ | exp Lrsh exp
+ {
+ $$ = mkbin(Orsh, $1, $3);
+ }
+ | exp Llsh exp
+ {
+ $$ = mkbin(Olsh, $1, $3);
+ }
+ | exp '<' exp
+ {
+ $$ = mkbin(Olt, $1, $3);
+ }
+ | exp '>' exp
+ {
+ $$ = mkbin(Ogt, $1, $3);
+ }
+ | exp Lleq exp
+ {
+ $$ = mkbin(Oleq, $1, $3);
+ }
+ | exp Lgeq exp
+ {
+ $$ = mkbin(Ogeq, $1, $3);
+ }
+ | exp Leq exp
+ {
+ $$ = mkbin(Oeq, $1, $3);
+ }
+ | exp Lneq exp
+ {
+ $$ = mkbin(Oneq, $1, $3);
+ }
+ | exp '&' exp
+ {
+ $$ = mkbin(Oand, $1, $3);
+ }
+ | exp '^' exp
+ {
+ $$ = mkbin(Oxor, $1, $3);
+ }
+ | exp '|' exp
+ {
+ $$ = mkbin(Oor, $1, $3);
+ }
+ | exp Lcons exp
+ {
+ $$ = mkbin(Ocons, $1, $3);
+ }
+ | exp Landand exp
+ {
+ $$ = mkbin(Oandand, $1, $3);
+ }
+ | exp Loror exp
+ {
+ $$ = mkbin(Ooror, $1, $3);
+ }
+ ;
+
+monexp : term
+ | '+' monexp
+ {
+ $2->src.start = $1.start;
+ $$ = $2;
+ }
+ | '-' monexp
+ {
+ $$ = mkunary(Oneg, $2);
+ $$->src.start = $1.start;
+ }
+ | '!' monexp
+ {
+ $$ = mkunary(Onot, $2);
+ $$->src.start = $1.start;
+ }
+ | '~' monexp
+ {
+ $$ = mkunary(Ocomp, $2);
+ $$->src.start = $1.start;
+ }
+ | '*' monexp
+ {
+ $$ = mkunary(Oind, $2);
+ $$->src.start = $1.start;
+ }
+ | Linc monexp
+ {
+ $$ = mkunary(Opreinc, $2);
+ $$->src.start = $1.start;
+ }
+ | Ldec monexp
+ {
+ $$ = mkunary(Opredec, $2);
+ $$->src.start = $1.start;
+ }
+ | Lcomm monexp
+ {
+ $$ = mkunary(Orcv, $2);
+ $$->src.start = $1.start;
+ }
+ | Lhd monexp
+ {
+ $$ = mkunary(Ohd, $2);
+ $$->src.start = $1.start;
+ }
+ | Ltl monexp
+ {
+ $$ = mkunary(Otl, $2);
+ $$->src.start = $1.start;
+ }
+ | Llen monexp
+ {
+ $$ = mkunary(Olen, $2);
+ $$->src.start = $1.start;
+ }
+ | Lref monexp
+ {
+ $$ = mkunary(Oref, $2);
+ $$->src.start = $1.start;
+ }
+ | Ltagof monexp
+ {
+ $$ = mkunary(Otagof, $2);
+ $$->src.start = $1.start;
+ }
+ | Larray '[' exp ']' Lof type
+ {
+ $$ = mkn(Oarray, $3, nil);
+ $$->ty = mktype(&$1.start, &$6->src.stop, Tarray, $6, nil);
+ $$->src = $$->ty->src;
+ }
+ | Larray '[' exp ']' Lof '{' initlist '}'
+ {
+ $$ = mkn(Oarray, $3, $7);
+ $$->src.start = $1.start;
+ $$->src.stop = $8.stop;
+ }
+ | Larray '[' ']' Lof '{' initlist '}'
+ {
+ $$ = mkn(Onothing, nil, nil);
+ $$->src.start = $2.start;
+ $$->src.stop = $3.stop;
+ $$ = mkn(Oarray, $$, $6);
+ $$->src.start = $1.start;
+ $$->src.stop = $7.stop;
+ }
+ | Llist Lof '{' celist '}'
+ {
+ $$ = etolist($4);
+ $$->src.start = $1.start;
+ $$->src.stop = $5.stop;
+ }
+ | Lchan Lof type
+ {
+ $$ = mkn(Ochan, nil, nil);
+ $$->ty = mktype(&$1.start, &$3->src.stop, Tchan, $3, nil);
+ $$->src = $$->ty->src;
+ }
+ | Lchan '[' exp ']' Lof type
+ {
+ $$ = mkn(Ochan, $3, nil);
+ $$->ty = mktype(&$1.start, &$6->src.stop, Tchan, $6, nil);
+ $$->src = $$->ty->src;
+ }
+ | Larray Lof Ltid monexp
+ {
+ $$ = mkunary(Ocast, $4);
+ $$->ty = mktype(&$1.start, &$4->src.stop, Tarray, mkidtype(&$<tok.src>3, $3), nil);
+ $$->src = $$->ty->src;
+ }
+ | Ltid monexp
+ {
+ $$ = mkunary(Ocast, $2);
+ $$->src.start = $<tok.src>1.start;
+ $$->ty = mkidtype(&$$->src, $1);
+ }
+ | Lid monexp
+ {
+ $$ = mkunary(Ocast, $2);
+ $$->src.start = $<tok.src>1.start;
+ $$->ty = mkidtype(&$$->src, $1);
+ }
+ | fixtype monexp
+ {
+ $$ = mkunary(Ocast, $2);
+ $$->src.start = $<tok.src>1.start;
+ $$->ty = $1;
+ }
+ ;
+
+term : idatom
+ | term '(' zelist ')'
+ {
+ $$ = mkn(Ocall, $1, $3);
+ $$->src.start = $1->src.start;
+ $$->src.stop = $4.stop;
+ }
+ | '(' elist ')'
+ {
+ $$ = $2;
+ if($2->op == Oseq)
+ $$ = mkn(Otuple, rotater($2), nil);
+ else
+ $$->flags |= PARENS;
+ $$->src.start = $1.start;
+ $$->src.stop = $3.stop;
+ }
+ | term '.' Lid
+ {
+ $$ = mkbin(Odot, $1, mkname(&$<tok.src>3, $3));
+ }
+ | term Lmdot term
+ {
+ $$ = mkbin(Omdot, $1, $3);
+ }
+ | term '[' export ']'
+ {
+ $$ = mkbin(Oindex, $1, $3);
+ $$->src.stop = $4.stop;
+ }
+ | term '[' zexp ':' zexp ']'
+ {
+ if($3->op == Onothing)
+ $3->src = $4;
+ if($5->op == Onothing)
+ $5->src = $4;
+ $$ = mkbin(Oslice, $1, mkbin(Oseq, $3, $5));
+ $$->src.stop = $6.stop;
+ }
+ | term Linc
+ {
+ $$ = mkunary(Oinc, $1);
+ $$->src.stop = $2.stop;
+ }
+ | term Ldec
+ {
+ $$ = mkunary(Odec, $1);
+ $$->src.stop = $2.stop;
+ }
+ | Lsconst
+ {
+ $$ = mksconst(&$<tok.src>1, $1);
+ }
+ | Lconst
+ {
+ $$ = mkconst(&$<tok.src>1, $1);
+ if($1 > 0x7fffffff || $1 < -0x7fffffff)
+ $$->ty = tbig;
+ $$ = $$;
+ }
+ | Lrconst
+ {
+ $$ = mkrconst(&$<tok.src>1, $1);
+ }
+ | term '[' exportlist ',' export ']'
+ {
+ $$ = mkbin(Oindex, $1, rotater(mkbin(Oseq, $3, $5)));
+ $$->src.stop = $6.stop;
+ }
+ ;
+
+idatom : Lid
+ {
+ $$ = mkname(&$<tok.src>1, $1);
+ }
+ | Lnil
+ {
+ $$ = mknil(&$<tok.src>1);
+ }
+ ;
+
+idterm : '(' idlist ')'
+ {
+ $$ = mkn(Otuple, rotater($2), nil);
+ $$->src.start = $1.start;
+ $$->src.stop = $3.stop;
+ }
+ ;
+
+exportlist : export
+ | exportlist ',' export
+ {
+ $$ = mkbin(Oseq, $1, $3);
+ }
+ ;
+
+export : exp
+ | texp
+ ;
+
+texp : Ltid
+ {
+ $$ = mkn(Otype, nil, nil);
+ $$->ty = mkidtype(&$<tok.src>1, $1);
+ $$->src = $$->ty->src;
+ }
+ | Larray Lof type
+ {
+ $$ = mkn(Otype, nil, nil);
+ $$->ty = mktype(&$1.start, &$3->src.stop, Tarray, $3, nil);
+ $$->src = $$->ty->src;
+ }
+ | Llist Lof type
+ {
+ $$ = mkn(Otype, nil, nil);
+ $$->ty = mktype(&$1.start, &$3->src.stop, Tlist, $3, nil);
+ $$->src = $$->ty->src;
+ }
+ | Lcyclic type
+ {
+ $$ = mkn(Otype, nil ,nil);
+ $$->ty = $2;
+ $$->ty->flags |= CYCLIC;
+ $$->src = $$->ty->src;
+ }
+ ;
+
+idexc : Lid
+ {
+ $$ = mkname(&$<tok.src>1, $1);
+ }
+ | /* empty */
+ {
+ $$ = nil;
+ }
+ ;
+
+idlist : idterm
+ | idatom
+ | idlist ',' idterm
+ {
+ $$ = mkbin(Oseq, $1, $3);
+ }
+ | idlist ',' idatom
+ {
+ $$ = mkbin(Oseq, $1, $3);
+ }
+ ;
+
+zelist :
+ {
+ $$ = nil;
+ }
+ | elist
+ {
+ $$ = rotater($1);
+ }
+ ;
+
+celist : elist
+ | elist ','
+ ;
+
+elist : exp
+ | elist ',' exp
+ {
+ $$ = mkbin(Oseq, $1, $3);
+ }
+ ;
+
+initlist : elemlist
+ {
+ $$ = rotater($1);
+ }
+ | elemlist ','
+ {
+ $$ = rotater($1);
+ }
+ ;
+
+elemlist : elem
+ | elemlist ',' elem
+ {
+ $$ = mkbin(Oseq, $1, $3);
+ }
+ ;
+
+elem : exp
+ {
+ $$ = mkn(Oelem, nil, $1);
+ $$->src = $1->src;
+ }
+ | qual Llabs exp
+ {
+ $$ = mkbin(Oelem, rotater($1), $3);
+ }
+ ;
+
+/*
+tpoly : ids Llabs '{' dfields '}'
+ {
+ $$ = typedecl($1, mktype(&$1->src.start, &$5.stop, Tpoly, nil, nil));
+ $$->left = rotater($4);
+ }
+ ;
+
+tpolys : tpoly
+ {
+ $$ = $1;
+ }
+ | tpolys tpoly
+ {
+ $$ = mkbin(Oseq, $1, $2);
+ }
+ ;
+*/
+
+tpolys : tpoly dfields
+ {
+ if($1->op == Oseq)
+ $1->right->left = rotater($2);
+ else
+ $1->left = rotater($2);
+ $$ = $1;
+ }
+ ;
+
+tpoly : ids Llabs
+ {
+ $$ = typedecl($1, mktype(&$1->src.start, &$2.stop, Tpoly, nil, nil));
+ }
+ | tpoly dfields ids Llabs
+ {
+ if($1->op == Oseq)
+ $1->right->left = rotater($2);
+ else
+ $1->left = rotater($2);
+ $$ = mkbin(Oseq, $1, typedecl($3, mktype(&$3->src.start, &$4.stop, Tpoly, nil, nil)));
+ }
+ ;
+
+%%
+
+static char *mkfileext(char*, char*, char*);
+static void usage(void);
+
+static int dosym;
+static int toterrors;
+static ulong canonnanbits[] = { 0x7fffffff, 0xffffffff};
+static char* infile;
+
+#define SLASHMOD "/module"
+
+static char*
+getroot(void)
+{
+ int n;
+ char *e, *l, *s;
+
+ if((e = getenv("EMU")) != nil){
+ for(s = e; *e != '\0'; e++){
+ if(*e == '-' && *(e+1) == 'r' && (e == s || *(e-1) == ' ' || *(e-1) == '\t')){
+ e += 2;
+ l = strchr(e, ' ');
+ if(l != nil)
+ *l = '\0';
+ if((n = strlen(e)) > 0){
+ s = malloc(n+1);
+ strcpy(s, e);
+ return s;
+ }
+ }
+ }
+ }
+ if((e = getenv("ROOT")) != nil)
+ return strdup(e);
+ return nil;
+}
+
+void
+main(int argc, char *argv[])
+{
+ char *s, *ofile, *ext, *root;
+ int i;
+
+ FPinit();
+ FPcontrol(0, INVAL|ZDIV|OVFL|UNFL|INEX);
+ canonnan = canontod(canonnanbits);
+
+ fmtinstall('D', dotconv);
+ fmtinstall('I', instconv);
+ fmtinstall('K', declconv);
+ fmtinstall('k', storeconv);
+ fmtinstall('L', lineconv);
+ fmtinstall('M', mapconv);
+ fmtinstall('n', nodeconv); /* exp structure */
+ fmtinstall('O', opconv);
+ fmtinstall('g', gfltconv);
+ fmtinstall('Q', etconv); /* src expression with type */
+ fmtinstall('R', ctypeconv); /* c equivalent type */
+ fmtinstall('P', ctypeconv); /* c equivalent type - pointer type */
+ fmtinstall('T', typeconv); /* source style types */
+ fmtinstall('t', stypeconv); /* structurally descriptive type */
+ fmtinstall('U', srcconv);
+ fmtinstall('v', expconv); /* src expression */
+ fmtinstall('V', expconv); /* src expression in '' */
+ lexinit();
+ typeinit();
+ optabinit();
+
+ gendis = 1;
+ asmsym = 0;
+ maxerr = 20;
+ ofile = nil;
+ ext = nil;
+ ARGBEGIN{
+ case 'D':
+ /*
+ * debug flags:
+ *
+ * a alt compilation
+ * A array constructor compilation
+ * b boolean and branch compilation
+ * c case compilation
+ * d function declaration
+ * D descriptor generation
+ * e expression compilation
+ * E addressable expression compilation
+ * f print arguments for compiled functions
+ * F constant folding
+ * g print out globals
+ * m module declaration and type checking
+ * n nil references
+ * s print sizes of output file sections
+ * S type signing
+ * t type checking function bodies
+ * T timing
+ * v global var and constant compilation
+ * x adt verification
+ * Y tuple compilation
+ * z Z bug fixes
+ */
+ s = ARGF();
+ while(s && *s)
+ debug[*s++] = 1;
+ break;
+ case 'I':
+ s = ARGF();
+ if(s == nil)
+ usage();
+ addinclude(s);
+ break;
+ case 'G':
+ asmsym = 1;
+ break;
+ case 'S':
+ gendis = 0;
+ break;
+ case 'a':
+ emitstub = 1;
+ break;
+ case 'A':
+ emitstub = emitdyn = 1;
+ break;
+ case 'c':
+ mustcompile = 1;
+ break;
+ case 'C':
+ dontcompile = 1;
+ break;
+ case 'e':
+ maxerr = 1000;
+ break;
+ case 'f':
+ isfatal = 1;
+ break;
+ case 'F':
+ newfnptr = 1;
+ break;
+ case 'g':
+ dosym = 1;
+ break;
+ case 'i':
+ dontinline = 1;
+ break;
+ case 'o':
+ ofile = ARGF();
+ break;
+ case 'O':
+ optims = 1;
+ break;
+ case 's':
+ s = ARGF();
+ if(s != nil)
+ fixss = atoi(s);
+ break;
+ case 't':
+ emittab = ARGF();
+ if(emittab == nil)
+ usage();
+ break;
+ case 'T':
+ emitcode = ARGF();
+ if(emitcode == nil)
+ usage();
+ break;
+ case 'd':
+ emitcode = ARGF();
+ if(emitcode == nil)
+ usage();
+ emitdyn = 1;
+ break;
+ case 'w':
+ superwarn = dowarn;
+ dowarn = 1;
+ break;
+ case 'x':
+ ext = ARGF();
+ break;
+ case 'X':
+ signdump = ARGF();
+ break;
+ case 'z':
+ arrayz = 1;
+ break;
+ default:
+ usage();
+ break;
+ }ARGEND
+
+ if((root = getroot()) != nil){
+ char *r;
+
+ r = malloc(strlen(root)+strlen(SLASHMOD)+1);
+ strcpy(r, root);
+ strcat(r, SLASHMOD);
+ addinclude(r);
+ free(root);
+ }
+ else
+ addinclude(INCPATH);
+
+ if(argc == 0){
+ usage();
+ }else if(ofile != nil){
+ if(argc != 1)
+ usage();
+ translate(argv[0], ofile, mkfileext(ofile, ".dis", ".sbl"));
+ }else{
+ if(ext == nil){
+ ext = ".s";
+ if(gendis)
+ ext = ".dis";
+ }
+ for(i = 0; i < argc; i++){
+ s = strrchr(argv[i], '/');
+ if(s == nil)
+ s = argv[i];
+ else
+ s++;
+ if(argc > 1)
+ print("%s:\n", argv[i]);
+ ofile = mkfileext(s, ".b", ext);
+ translate(argv[i], ofile, mkfileext(ofile, ext, ".sbl"));
+ }
+ }
+ if(toterrors)
+ exits("errors");
+ exits(0);
+}
+
+static void
+usage(void)
+{
+ fprint(2, "usage: limbo [-CGSacgwe] [-I incdir] [-o outfile] [-{T|t|d} module] [-D debug] file ...\n");
+ exits("usage");
+}
+
+static char*
+mkfileext(char *file, char *oldext, char *ext)
+{
+ char *ofile;
+ int n, n2;
+
+ n = strlen(file);
+ n2 = strlen(oldext);
+ if(n >= n2 && strcmp(&file[n-n2], oldext) == 0)
+ n -= n2;
+ ofile = malloc(n + strlen(ext) + 1);
+ memmove(ofile, file, n);
+ strcpy(ofile+n, ext);
+ return ofile;
+}
+
+void
+translate(char *in, char *out, char *dbg)
+{
+ Decl *entry;
+ int doemit;
+
+ infile = in;
+ outfile = out;
+ symfile = dbg;
+ errors = 0;
+ bins[0] = Bopen(in, OREAD);
+ if(bins[0] == nil){
+ fprint(2, "can't open %s: %r\n", in);
+ toterrors++;
+ return;
+ }
+ doemit = emitstub || emittab || emitcode;
+ if(!doemit){
+ bout = Bopen(out, OWRITE);
+ if(bout == nil){
+ fprint(2, "can't open %s: %r\n", out);
+ toterrors++;
+ Bterm(bins[0]);
+ return;
+ }
+ if(dosym){
+ bsym = Bopen(dbg, OWRITE);
+ if(bsym == nil)
+ fprint(2, "can't open %s: %r\n", dbg);
+ }
+ }
+
+ lexstart(in);
+
+ popscopes();
+ typestart();
+ declstart();
+
+ yyparse();
+
+ entry = typecheck(!doemit);
+
+ modcom(entry);
+
+ fns = nil;
+ nfns = 0;
+ descriptors = nil;
+
+ if(bout != nil)
+ Bterm(bout);
+ if(bsym != nil)
+ Bterm(bsym);
+ toterrors += errors;
+ if(errors && bout != nil)
+ remove(out);
+ if(errors && bsym != nil)
+ remove(dbg);
+}
+
+void
+trapFPE(unsigned exception[5], int value[2])
+{
+ /* can't happen; it's just here to keep FPinit happy. */
+ USED(exception);
+ USED(value);
+}
+
+static char *
+win2inf(char *s)
+{
+ int nt = 0;
+ char *t;
+
+ if(strlen(s) > 1 && s[1] == ':'){
+ s[1] = '/';
+ s++;
+ nt = 1;
+ }
+ for(t = s; *t != '\0'; t++){
+ if(*t == '\\')
+ *t = '/';
+ if(nt)
+ *t = tolower(*t);
+ }
+ return s;
+}
+
+static char *cd;
+
+/*
+static char *
+pwd(void)
+{
+ int ok, qid, l1, l2;
+ Dir d;
+ char *p;
+ char hd[64], buf[128], path[256];
+
+ if(cd != nil)
+ return cd;
+ *hd = *path = '\0';
+ qid = -1;
+ strcpy(buf, ".");
+ for(;;){
+ ok = dirstat(buf, &d);
+ if(ok < 0)
+ return "";
+ if(d.qid.path == qid && strcmp(d.name, hd) == 0)
+ break;
+ l1 = strlen(d.name);
+ l2 = strlen(path);
+ memmove(path+l1+1, path, l2+1);
+ memcpy(path+1, d.name, l1);
+ path[0] = '/';
+ strcpy(hd, d.name);
+ qid = d.qid.path;
+ strcat(buf, "/..");
+ }
+ p = win2inf(path);
+ while(*p == '/' && p[1] == '/')
+ p++;
+ cd = malloc(strlen(p)+1);
+ strcpy(cd, p);
+ return cd;
+}
+*/
+
+static char *
+cleann(char *s)
+{
+ char *p, *r, *t;
+ char buf[256];
+
+ r = t = malloc(strlen(s)+1);
+ strcpy(t, s);
+ t = win2inf(t);
+ if(*t != '/'){
+ /* p = pwd(); */
+ p = win2inf(getwd(buf, sizeof(buf)));
+ s = malloc(strlen(p)+strlen(t)+2);
+ strcpy(s, p);
+ strcat(s, "/");
+ strcat(s, t);
+ }
+ else{
+ s = malloc(strlen(t)+1);
+ strcpy(s, t);
+ }
+ free(r);
+ /* print("cleann: %s\n", p); */
+ return cleanname(s);
+}
+
+char *
+srcpath(char *name, int nlen)
+{
+ int l1, l2;
+ char *r, *srcp, *t;
+
+ srcp = cleann(infile);
+ r = getroot();
+ if(r == nil){
+ l1 = strlen(INCPATH);
+ r = malloc(l1+1);
+ strcpy(r, INCPATH);
+ if(l1 >= strlen(SLASHMOD) && strcmp(r+l1-strlen(SLASHMOD), SLASHMOD) == 0)
+ r[l1-strlen(SLASHMOD)] = '\0';
+ }
+ t = cleann(r);
+ free(r);
+ r = t;
+ /* srcp relative to r */
+ l1 = strlen(srcp);
+ l2 = strlen(r);
+ if(l1 >= l2 && strncmp(srcp, r, l2) == 0){
+ /* nothing to do */
+ }else
+ l2 = 0;
+ strncpy(name, srcp+l2, nlen);
+ name[nlen-1] = '\0';
+ free(r);
+ free(srcp);
+ /* print("srcpath: %s\n", name); */
+ return name;
+}