/* * Define a function. * Name and parenthesis was already seen and defined. */ function() { extern declare, blkhed, blkend; extern printf, statement, peeksym, cval, symbol, retseq; extern paraml; auto o; /* Emit prologue. */ printf(".text; 1:mov r5,-(sp); mov sp,r5\n"); /* Declare arguments. */ declare(8); /* Declare argument types. */ declist(); /* Parse statement, this is assumed to be a block. */ statement(1); /* Emit return. */ retseq(); } extdef() { extern eof, function, cval; extern symbol, block, printf, pname, errflush, csym[]; extern error; auto o, c, cs[]; char s[]; if(((o=symbol())==0) | o==1) /* EOF */ return; /* * External definitions have to start with a name, * not with a keyword. * This means functions can only return int, * external variables can only be defined as ints. */ if(o!=20) goto syntax; /* Declare external. */ csym[0] = 6; cs = &csym[4]; printf(".globl %p\n", cs); /* Functions and vectors are actually pointers. */ s = ".data; %p:1f\n"; switch(o=symbol()) { case 6: /* ( */ printf(s, cs); function(); return; case 21: /* const */ printf(".data; %p: %o\n", cs, cval); if((o=symbol())!=1) /* ; */ goto syntax; return; case 1: /* ; */ printf(".bss; %p: .=.+2\n", cs); return; case 4: /* [ */ c = 0; if((o=symbol())==21) { /* const */ /* Size of array, type can only be int. */ c = cval<<1; o = symbol(); } if(o!=5) /* ] */ goto syntax; printf(s, cs); if((o=symbol())==1) { /* ; */ /* Uninitialized vector is stored in bss. */ printf(".bss; 1:.=.+%o\n", c); return; } /* * Put initialized elements into data segment. * Only simple constants are allowed here. */ printf("1:"); while(o==21) { /* const */ printf("%o\n", cval); c =- 2; if((o=symbol())==1) /* ; */ goto done; if(o!=9) /* , */ goto syntax; else o = symbol(); } goto syntax; done: /* Fill the rest with zeroes. */ if(c>0) printf(".=.+%o\n", c); return; case 0: /* EOF */ return; } syntax: error("External definition syntax"); errflush(o); statement(0); } /* Parse a statement. If d is true, this is the body of a function. */ statement(d) { extern symbol, error, blkhed, eof, peeksym; extern blkend, csym[], rcexpr, block[], tree[], regtab[]; extern retseq, jumpc, jump, label, contlab, brklab, cval; extern swp[], isn, pswitch, peekc, slabel; extern efftab[], declare, deflab, errflush, swtab[], swsiz, branch; int o, o1, o2, o3, np[]; stmt: switch(o=symbol()) { /* EOF */ case 0: error("Unexpected EOF"); /* ; */ case 1: /* } */ case 3: return; /* { */ case 2: { if(d) blkhed(); while (!eof) { if ((o=symbol())==3) /* } */ goto bend; peeksym = o; statement(0); } error("Missing '}'"); bend: return; } /* keyword */ case 19: /* * Statements that define a break or continue label * save the current ones on the stack and restore * them afterwards. * Similarly a switch pushes the current switch table, * the break and default labels. */ switch(cval) { /* goto */ case 10: o1 = block(1,102,0,0,tree()); rcexpr(o1, regtab); goto semi; /* return */ case 11: if((peeksym=symbol())==6) /* ( */ rcexpr(pexpr(), regtab); retseq(); goto semi; /* if */ case 12: /* Jump away if condition false. */ jumpc(pexpr(), o1=isn++, 0); statement(0); if ((o=symbol())==19 & cval==14) { /* else */ o2 = isn++; /* Done with if, jump to end. */ (easystmt()?branch:jump)(o2); /* Else */ label(o1); statement(0); label(o2); return; } peeksym = o; label(o1); return; /* while */ case 13: o1 = contlab; o2 = brklab; /* Continue goes to the loop test. */ label(contlab = isn++); /* Break if condition is false. */ jumpc(pexpr(), brklab=isn++, 0); /* Loop body */ o3 = easystmt(); statement(0); /* Next iteration */ (o3?branch:jump)(contlab); /* End of loop */ label(brklab); contlab = o1; brklab = o2; return; /* break */ case 17: if(brklab==0) error("Nothing to break from"); jump(brklab); goto semi; /* continue */ case 18: if(contlab==0) error("Nothing to continue"); jump(contlab); goto semi; /* do */ case 19: o1 = contlab; o2 = brklab; contlab = isn++; brklab = isn++; label(o3 = isn++); statement(0); /* Continue goes to the loop test. */ label(contlab); contlab = o1; if ((o=symbol())==19 & cval==13) { /* while */ /* * Jump to top if condition is true. * NB: No parenthese required for condition. */ jumpc(tree(), o3, 1); /* End of loop */ label(brklab); brklab = o2; goto semi; } goto syntax; /* case */ case 16: if ((o=symbol())!=21) /* constant */ goto syntax; if ((o=symbol())!=8) /* : */ goto syntax; if (swp==0) { error("Case not in switch"); goto stmt; } if(swp>=swtab+swsiz) { error("Switch table overflow"); } else { *swp++ = isn; *swp++ = cval; label(isn++); } goto stmt; /* switch */ case 15: o1 = brklab; brklab = isn++; /* Expression to be switched on must be an integer. */ np = pexpr(); if (np[1]>1 & np[1]<16) error("Integer required"); rcexpr(np, regtab); /* Switch body */ pswitch(); brklab = o1; return; /* default */ case 20: if (swp==0) error("Default not in switch"); if ((o=symbol())!=8) /* : */ goto syntax; deflab = isn++; label(deflab); goto stmt; } error("Unknown keyword"); goto syntax; /* name */ case 20: if (peekc==':') { /* Define a label. */ peekc = 0; if (csym[0]>0) { error("Redefinition"); goto stmt; } csym[0] = 2; csym[1] = 020; /* int[] */ /* When is csym[2] != 0? */ if (csym[2]==0) csym[2] = isn++; /* Store pointer to location. */ slabel(); goto stmt; } } /* If all else fails, assume an expression statement. */ peeksym = o; rcexpr(tree(), efftab); goto semi; semi: if ((o=symbol())!=1) /* ; */ goto syntax; return; syntax: error("Statement syntax"); errflush(o); goto stmt; } /* Parse a parenthesized expression. */ pexpr() { auto o, t; if ((o=symbol())!=6) /* ( */ goto syntax; t = tree(); if ((o=symbol())!=7) /* ) */ goto syntax; return(t); syntax: error("Statement syntax"); errflush(o); return(0); } /* Parse a switch body. */ pswitch() { extern swp[], isn, swtab[], printf, deflab, statement, brklab; extern label; int sswp[], dl, cv, swlab; sswp = swp; if (swp==0) swp = swtab; swlab = isn++; /* Switch subroutine implemented in libc. */ printf("jsr pc,bswitch; l%d\n", swlab); /* Push old default label and undefine it. */ dl = deflab; deflab = 0; /* The actual switch body. */ statement(0); /* If default wasn't defined, put it after the switch. */ if (!deflab) { deflab = isn++; label(deflab); } /* Write switch table. */ printf("L%d:.data;L%d:", brklab, swlab); while(swp>sswp & swp>swtab) { cv = *--swp; printf("%o; l%d\n", cv, *--swp); } printf("L%d; 0\n.text\n", deflab); /* Pop old switch. */ deflab = dl; swp = sswp; } /* * Begin a function block. Assign stack offsets to local variables. * Stack frame looks like this: * * paramn * 6 ... * 4 param1 * 2 ret * 0 r5 <- r5 * -2 auto1 * -4 ... * auton */ blkhed() { extern symbol, cval, declare, peeksym, paraml[], parame[]; extern error, length, rlength, setstk, defvec, isn, defstat; extern stack, hshtab[], hshsiz, pssiz; int o, al, pl, cs[], hl; declist(); stack = al = -2; /* Current automatic length/stack depth */ pl = 4; /* Current parameter length */ /* Walk parameter list and assign stack offsets. */ while(paraml) { *parame = 0; paraml = *(cs = paraml); cs[2] = pl; /* Temporary parameter class. */ *cs = 10; /* Advance stack. */ pl =+ rlength(cs[1]); } /* Walk symbol table and handle all locally declared variables. */ cs = hshtab; hl = hshsiz; while(hl--) { if (cs[4]) switch(cs[0]) { /* sort unmentioned */ case 0177776: /* -2 */ cs[0] = 5; /* auto */ /* auto */ case 5: if (cs[3]) { /* vector */ /* Dereference type, multiply by length and align. */ al =- (cs[3]*length(cs[1]-020)+1) & 077776; /* Use sp to setstk(al); defvec(al); } cs[2] = al; al =- rlength(cs[1]); goto loop; /* parameter */ case 10: /* Convert to auto. */ cs[0] = 5; goto loop; /* static */ case 7: /* Assign a label and define the variable there. */ cs[2] = isn++; defstat(cs); goto loop; loop:; } cs = cs+pssiz; } setstk(al); } /* * Empty hash table from names after external definition. * It is an error to use an undefined symbol. */ blkend() { extern hshtab[], hshsiz, pssiz, hshused; auto i, hl; i = 0; hl = hshsiz; while(hl--) { if(hshtab[i+4]) if (hshtab[i]==0) error("%p undefined", &hshtab[i+4]); if(hshtab[i]!=1) { /* not keyword */ hshused--; hshtab[i+4] = 0; } i =+ pssiz; } } /* Skip symbols until some sensible point. */ errflush(o) { extern symbol, peeksym, eof; while(o>3) /* ; { } */ o = symbol(); peeksym = o; } /* * Declare symbols as long as a list of symbols * starts with a type keyword. */ declist() { extern peeksym, peekc, csym[], cval; auto o; while((o=symbol())==19 & cval<10) declare(cval); peeksym = o; } /* * See what the next statement will be. * If it's an easy statement it will be short and can be branched over. * Otherwise a jump may be needed. */ easystmt() { extern peeksym, peekc, cval; if((peeksym=symbol())==20) /* name */ return(peekc!=':'); /* not label */ if (peeksym==19) { /* keyword */ switch(cval) case 10: /* goto */ case 11: /* return */ case 17: /* break */ case 18: /* continue */ return(1); return(0); } return(peeksym!=2); /* { */ } branch(lab) { printf("br L%d\n", lab); }