home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / suntar1.cpt / gc / gen.c < prev    next >
Encoding:
Text File  |  1992-06-06  |  33.2 KB  |  1,350 lines

  1. /*****************************\
  2. *                             *
  3. *      Code Generator         *
  4. *                             *
  5. \*****************************/
  6.  
  7.  
  8.  
  9.  
  10. /*
  11. Question: why in most compilers it's so difficult to see the generated code ?
  12. Answer: because the generated code is often so bad that if you should examine it
  13.     carefully, you would think that it's better to try another compiler
  14. This code generator shows its code on screen, hence its code had to be
  15. tolerably good, but I wanted to write a simple one-pass code generator,
  16. and the only well-known one-pass optimizing technique is peephole optimization.
  17. Choosing an accumulator-based architecture helped, since there is no
  18. need for any register allocation strategy, but that was not enough.
  19. This program uses a few techniques, including a very restricted form
  20. of peephole optimization, but the big work is done in another way.
  21. Most compilers generate bad code knowing that later optimizing passes will
  22. modify it, but this code generator had to be one-pass, hence it had to
  23. identify bad code BEFORE generating it.
  24. So, I chose a rarely used method, the "lazy evaluation" or "approching
  25. deadline" technique.
  26. Really, that philosophy sounds familiar to me, and I prefer to call it
  27. the "lazy Italian" technique. You see, Italians are of the
  28. same race as Mexicans, and maybe you remember those movies with a peone
  29. who must do a work: he takes out the working tools, then he thinks:
  30. today I've done enough, I'll do the rest tomorrow. And tomorrow he
  31. does a siesta. But Italians are slightly different, when the deadline
  32. approaches they remember that they belong to the most civil people in the
  33. world, and they know that they must do the job, so they do it and they do
  34. it wonderfully well. Obviously, since so much work has accumulated they may
  35. use some technique which would not be possible otherwise, exploiting the
  36. mass of things to do: this code generator realizes that the delayed work
  37. could benefit from the new information it gathered in the meantime and
  38. exploits it.
  39.  
  40. More technically: an expression is NOT left in a fixed state: there is a
  41. standard struct which may say "I've generated all the code to compute
  42. the expression into register A (Accumulator) or X (Index), but it might
  43. also say "no code was generated, all the informations are stored in this
  44. struct" or a mixed situation (some code was generated, but it did not
  45. compute the final expression, only a part of it, the rest is stored in the
  46. struct).
  47. There is only one struct, but for a two-operand operator there are,
  48. temporarily, two. The two operands and the operation on them must always be
  49. represented by a single resulting struct when one arrives to their end (the
  50. deadline), and that could oblige to generate code, but (lazy attitude) the
  51. program never generates more code than is strictly necessary to bring the
  52. expression to a valid state of the struct, and tries all ways (i.e.
  53. optimizations !) to avoid generating that code, or to avoid generating many
  54. instructions.
  55. Then there are some functions as ForceA, ForceGenerated etc. that oblige
  56. the code generator to bring the struct to a state or to one of a group
  57. of states (obviously the one that requires less work...)
  58.  
  59. The possible states are:
  60. immediate: the value of the expression is stored in the struct (rvalue only)
  61. *immediate or immediate+1: the absolute, nonrelocatable address of the
  62.     variable containing the value of the expression is stored in the
  63.     struct (l/rvalue)
  64. simplevar: the struct stores a pointer to a symbol table entry which
  65.     describes the variable, either absolute or dynamic (l/rvalue), plus
  66.     an offset (usually 0)
  67. *simplevar or simplevar+1: as above, but with an added indirection,
  68.     the variable contains the address of the variable  (good for
  69.     VAR-parameter passing) (l/rvalue)
  70. relocatable: the value is a constant value plus the address of an absolute
  71.     variable (the pointer to symbol table is stored as a 16-bit
  72.     offset) minus another absolute address (rvalue only)
  73. based: the program generated code to store a value into X, to which it
  74.     must add the fixed offset stored in the struct in order to
  75.     get the address of the variable containing the value (l/rvalue)
  76. generated: the program generated code to store a value into A or X, the
  77.     struct contains only a boolean to tell which register (rvalue only)
  78. flags: the boolean expression is true if the generated code during execution
  79.     will jump to labelTrue or if a conditional branch placed AFTER all
  80.     the previously generated code will find true the "condition", it's
  81.     false in case of a jump to labelFalse or if the condition is false
  82.     (rvalue only). That seems complex, but it's the key to the optimization
  83.     of && and ||.
  84. Finally, there are two temporary states that are NOT coded in the struct
  85. (the function which generated them must remember that):
  86. Stack: as generated, followed by the generation of a PUSH
  87. Jump: as flags, followed by the generation of a branch testing "condition"
  88.  
  89.  
  90. Written by Gabriele Speranza, summer 1990
  91. modified by rearranging and enlarging the set of possible
  92. expression states, november 1990
  93. */
  94.  
  95.  
  96. #include <stdio.h>
  97.  
  98. #include "gc.h"
  99.  
  100.  
  101.  
  102.  
  103. /* #define hidden static */
  104. #define hidden /**/
  105. /* i soliti problemi di librerie non del tutto compatibili: */
  106.  
  107. movmem(src, dest, len)
  108. register char*dest,*src;
  109. register int len;
  110. {
  111.      while (--len>=0) *dest++ = *src++;
  112. }
  113.  
  114. word newlabel();
  115. void InitSecOp(),BinaryOp(),Bflush(),BEmit();
  116.  
  117. static word lastWasLabel=0;
  118. static char *AX[2]={"A","X"};
  119.  
  120. /*********************/
  121. hidden void AddressingMode(expr)
  122. localmem*expr;
  123. {
  124. switch(expr->class){
  125. case immediate:
  126.     fprintf(out,"#%ld",expr->eval);break;
  127. case immediate+1:
  128.     fprintf(out,"%ld",expr->eval);break;
  129. case simplevar:
  130.     if(expr->displacement!=0)
  131.        fprintf(out,"%d+",expr->displacement);
  132.     fprintf(out,"%s",expr->sTable->name);
  133.     if(expr->sTable->typ==dyn)
  134.        fprintf(out,"(SP)");
  135.     break;
  136. case relocatable:
  137.     fprintf(out,"#");
  138.     if(expr->symplus==0)
  139.        fprintf(out,"%ld",expr->eval);
  140.     else{
  141.        if(expr->eval!=0)
  142.           fprintf(out,"%ld+",expr->eval);
  143.        {char*p=TOLONG(expr->symplus);
  144.        fprintf(out,"%s",((tabel*)p)->name);}
  145.        }
  146.     if(expr->symminus!=0){
  147.        char*p=TOLONG(expr->symminus);
  148.        fprintf(out,"-%s",((tabel*)p)->name);
  149.        }
  150.     break;
  151. case based:
  152.     if(expr->displacement==0)
  153.        fprintf(out,"(X)");
  154.     else
  155.        fprintf(out,"%d(X)",expr->displacement);
  156.     break;
  157. case generated:
  158.     fprintf(out,"%s",AX[expr->place]);
  159.     break;
  160. default:
  161. /*ìììì*/
  162. printf("%d %lx",expr->class,expr);
  163.     errore("???");
  164. }}
  165. /****************************/
  166.  
  167.  
  168. /* please excuse me if I did not use vararg and created a non-portable
  169. implementation: when I wrote it I knew rather little about post-K&R
  170. extensions of C and had never heard about vararg
  171. Anyway, it was written on the QL and ran without modifications on the Mac
  172. */
  173.  
  174.  
  175. void Emit(control /*...*/)
  176. char *control;
  177. {char **nextParameter = &control;
  178.  
  179. Bflush();
  180. if(!lastWasLabel)
  181.    fprintf(out,"    ");
  182. else
  183.    lastWasLabel=0;
  184. while(*control!='\0'){
  185.    if(*control=='%'){
  186.       control++;
  187.       if(*control=='n')
  188.          fprintf(out,"\n    ");
  189.       else if(*control=='s')
  190.          fprintf(out,"%s",*++nextParameter);
  191.       else if(*control=='e')
  192.          AddressingMode(*++nextParameter);
  193. /*      else if(*control=='l')
  194.          fprintf(out,"L%d",*++nextParameter);
  195. */
  196.       else if(*control=='d')
  197.          fprintf(out,"%ld",*++nextParameter);
  198.       else
  199.       /*ììì*/{
  200.       printf("control=%c",*control);
  201.          errore("???");    }
  202.       }
  203.    else
  204.       fprintf(out,"%c",*control);
  205.    control++;
  206.    } /* end while */
  207. fprintf(out,"\n");
  208. fflush(out);
  209. }
  210. /*******************/
  211.  
  212. /* an assembler usually accepts a forward reference, but it does not
  213. accept a forward reference to a forward reference, hence I can't simply
  214. emit EQU directives, I must store them until the label is emitted */
  215.  
  216.  
  217. static word EQUtab[10][2];
  218. static int lastEQU=0;
  219.  
  220. hidden void partition(lab)
  221. word lab;
  222. {int i;
  223. for(i=lastEQU-1;i>=0;i--)
  224.    if(EQUtab[i][1]==lab)
  225.       if(--lastEQU!=i){
  226.          word t;
  227.          EQUtab[i][1]=EQUtab[lastEQU][1];
  228.          t=EQUtab[i][0];
  229.          EQUtab[i][0]=EQUtab[lastEQU][0];
  230.          EQUtab[lastEQU][0]=t;
  231.          }
  232. }
  233.  
  234. hidden void LEmit(lab)
  235. word lab;
  236. {int i,f;
  237. if(lab==0)return;
  238. Bflush();
  239. if(lastWasLabel)fprintf(out,"\n");
  240. else lastWasLabel=1;
  241. fprintf(out,"L%d:",lab);
  242. if(lab<=9)fprintf(out," ");
  243. f=lastEQU; partition(lab);
  244. for(i=lastEQU;i<f;i++)
  245.    LEmit(EQUtab[1][0]);
  246. }
  247.  
  248. hidden void EQUforward(l1,l2)
  249. word l1,l2;
  250. {
  251. if(lastEQU==10)errore("too complex logic expr");
  252. EQUtab[lastEQU][0]=l1;
  253. EQUtab[lastEQU++][1]=l2;
  254. }
  255.  
  256. hidden void EQUbackwards(l1,l2)
  257. word l1,l2;
  258. {int i,f;
  259. if(lastWasLabel){
  260.    fprintf(out,"\n");
  261.    lastWasLabel=0;}
  262. fprintf(out,"L%d %sEQU L%d",l1,l1<=9?" ":"",l2);
  263. f=lastEQU; partition(l1);
  264. for(i=lastEQU;i<f;i++)
  265.    EQUbackwards(EQUtab[1][0],l2);
  266. }
  267. /********************/
  268. static byte bufferFull=0;
  269. static byte bufferVal;
  270. static localmem* bufferPt;
  271.  
  272. /* PUSHs and BRanches are not emitted immediately, they are stored
  273. in a buffer from which is flushed at the next Emit, but they may also
  274. be annihilated before being flushed.
  275. That's not only an optimization, it's essential to follow the rule that
  276. a costant expression may be used in every place a literal may be, including
  277. places (e.g. declarations) where code must NOT be generated, since the
  278. expression will only be entered as an attribute in the symbol table. And
  279. I could not avoid to call a LazyPUSH or LazyJMP before knowing whether
  280. the current expression is constant or not.
  281. */
  282.  
  283. hidden void LazyPUSH(plac)
  284. {
  285. Bflush();
  286. bufferFull=1;
  287. bufferVal=plac;
  288. }
  289. LazyPOP(plac)
  290. {
  291. if(!bufferFull)
  292.    Emit("POP %s",(long)AX[plac]);
  293. else
  294.    {if(plac!=bufferVal)
  295.       Emit("MOV %s,%s",(long)AX[plac],(long)AX[bufferVal]);
  296.    bufferFull=0;
  297.    }
  298. }
  299. hidden void LazyJMP(expr)
  300. localmem*expr;
  301. {if(bufferFull&&bufferVal==16+T)
  302.    expr->auxlabel=0xFFFF;
  303. else{
  304.    expr->auxlabel=0;
  305.    Bflush();
  306.    bufferFull=1;
  307.    bufferVal=16+T;
  308.    bufferPt=expr;
  309.    }
  310. }
  311. hidden void LazyLabel(expr)
  312. localmem*expr;
  313. {
  314. if(expr->auxlabel==0xFFFF)return;
  315. if(bufferFull&&bufferPt==expr)
  316.    bufferFull=0;
  317. else
  318.    LEmit(expr->auxlabel);
  319. }
  320. void Bflush()
  321. {
  322. if(!bufferFull)return;
  323. bufferFull=0;
  324. if(bufferVal<16)
  325.    Emit("PUSH %s",(long)AX[bufferVal]);
  326. else
  327.    BEmit(bufferVal&0xF,
  328.       bufferPt->auxlabel=newlabel());
  329.  
  330. }
  331.  
  332. hidden void BEmit(cond,lab)
  333. {
  334. static char *brCode=
  335.    "NOP\0BRA\0BEQ\0BNE\0BLE\0BGT\0BLT\0BGE";
  336. if(cond==F)return; /* niente NOP...*/
  337. Bflush();
  338. if(!lastWasLabel)
  339.    fprintf(out,"    ");
  340. else
  341.    lastWasLabel=0;
  342. fprintf(out,"%s L%d\n",&brCode[cond<<2],lab);
  343. }
  344. /*******************************/
  345. #define this currentExpr
  346. #define right currentExpr
  347. #define left (*first)
  348. #define son currentExpr
  349. #define issimple(x) (x.class<4)
  350. #define islazy(x) (x.class<5)
  351. #define INVERSE(x) ((x)^1)
  352. #define Flabel gci.aa.Label[0]
  353. #define Tlabel gci.aa.Label[1]
  354. static byte bitarray[]={5,0,4,2,1,2,2,0};
  355. #define isimr(x) (bitarray[x.class]&1)
  356. #define usesX(x) (bitarray[x.class]&2)
  357. #define isimsim(x) (bitarray[x.class]&4)
  358.  
  359. /********************/
  360. void ForceNative(expr)
  361. localmem*expr;
  362. {if(expr->class==simplevar+1){
  363.    expr->class=simplevar;
  364.    Emit("LOAD X,%e",expr);
  365.    expr->class=based;expr->displacement=0;
  366.    }
  367. }
  368. /********************/
  369. void ForceRvalue(expr)
  370. localmem*expr;
  371. {if(expr->lval)
  372.    expr->lval=expr->isCExpr=0;
  373. }
  374. /**********************************/
  375. void ForceA(expr)  /* solo per rvalue... */
  376. localmem*expr;
  377. {
  378. if(expr->class==generated){
  379.    if(expr->place!=0)
  380.       {Emit("MOV A,X");expr->place=0;}
  381.    return;
  382.    }
  383. else if(expr->class!=flags){
  384.    if(expr->class==immediate&&expr->eval==0)
  385.       Emit("CLR A");
  386.    else{
  387.       ForceNative(expr);
  388.       Emit("LOAD A,%e",expr);
  389.       }
  390.    expr->isCExpr=0;
  391.    }
  392. else{  /* flags */
  393.    if(expr->condition<=T&&expr->Flabel==0&&expr->Tlabel==0)
  394.       Emit(expr->condition==T?"LOAD A,#1":"CLR A");
  395.    else{
  396.       word t=newlabel();
  397.       if(expr->Flabel==0)
  398.          if(expr->Tlabel==0){
  399.             Emit("CLR A");
  400.             BEmit(INVERSE(expr->condition),t);
  401.             Emit("INC A");
  402.             }
  403.          else{
  404.             Emit("CLR A");
  405.             BEmit(INVERSE(expr->condition),t);
  406.             LEmit(expr->Tlabel);
  407.             Emit("LOAD A,#1");
  408.             }
  409.       else  /* Flabel!=0 */
  410.          if(expr->Tlabel==0){
  411.             Emit("LOAD A,#1");
  412.             BEmit(expr->condition,t);
  413.             LEmit(expr->Flabel);
  414.             Emit("CLR A");
  415.             }
  416.          else{
  417.             BEmit(INVERSE(expr->condition),expr->Tlabel);
  418.             LEmit(expr->Flabel);
  419.             Emit("CLR A");
  420.             BEmit(T,t);
  421.             LEmit(expr->Tlabel);
  422.             Emit("LOAD A,#1");
  423.             }
  424.       LEmit(t);
  425.       }
  426.    }
  427. expr->class=generated;
  428. expr->place=0;
  429. }
  430. /********************/
  431. void ForceX(expr) /* solo Rvalue !!! */
  432. localmem*expr;
  433. {
  434. if(expr->class==flags)
  435.    ForceA(expr);
  436. if(expr->class==generated){
  437.    if(!expr->place)
  438.       {Emit("MOV X,A");expr->place=1;}
  439.    return;
  440.    }
  441. ForceNative(expr);
  442. Emit("LOAD X,%e",expr);
  443. expr->class=generated;
  444. expr->place=1;expr->isCExpr=0;
  445. }
  446. /********************/
  447. void ForceFlags(expr)
  448. localmem*expr;
  449. {
  450. if(expr->class==flags)return;
  451. if(expr->class==immediate)
  452.    expr->condition=expr->eval?T:F;
  453. else{
  454.    ForceNative(expr);
  455.    if(expr->class==generated&&expr->place==1)
  456.       ForceA(expr); /* TEST X non esistente */
  457.    Emit("TEST %e",expr);
  458.    expr->condition=NE;
  459.    }
  460. expr->class=flags;
  461. expr->Flabel=expr->Tlabel=expr->isCExpr=0;
  462. }
  463. /********************/
  464. void ForceBased(expr)  /* solo per lvalue ! */
  465. localmem *expr;
  466. {ForceNative(expr);
  467. if(expr->class==based)return;
  468. Emit("LEA %e",expr);
  469. expr->class=based;
  470. expr->displacement=expr->isCExpr=0;
  471. }
  472. /********************/
  473. void ForceStack(expr)
  474. localmem*expr;
  475. {
  476. if(expr->class==generated&&expr->place!=0)
  477.    LazyPUSH(1);
  478. else{
  479.    ForceA(expr); LazyPUSH(0);
  480.    }
  481. /* expr->place=-1; */
  482. }
  483. /********************/
  484. void ForceJump(expr,direction)
  485. localmem*expr;
  486. {
  487. ForceFlags(expr);
  488. if(!expr->label[direction])
  489.    expr->label[direction]=newlabel();
  490. BEmit(expr->condition^(1-direction),
  491.    expr->label[direction]);
  492. LEmit(expr->label[1-direction]);
  493. /* expr->label[1-direction]=0;
  494.    expr->condition=-1; */
  495. }
  496. /********************/
  497. hidden word newlabel()
  498. {
  499. static word lastLab=0;
  500. return ++lastLab;
  501. }
  502. hidden void SuppressLabels(expr)
  503. localmem*expr;
  504. {if(expr->class!=flags)return;
  505. LEmit(expr->Flabel);LEmit(expr->Tlabel);
  506. /* expr->Flabel=expr->Tlabel=0; */
  507. }
  508. /*********************************/
  509. void primary(symbolTable)
  510. tabel *symbolTable;
  511. {
  512. if(symbolTable->typ==const){
  513.    this.class=immediate;
  514.    this.eval=symbolTable->val;
  515.    this.lval=0;this.isCExpr=1;
  516.    }
  517. else{
  518.    this.class=simplevar;
  519.    this.sTable=symbolTable;
  520.    this.displacement=0;
  521.    this.lval=1;
  522.    this.isCExpr=symbolTable->typ==ass;
  523.    }
  524. }
  525. /****************/
  526. void UnaryPre(op,features)
  527. char op;
  528. {
  529. if(features&lval1op)
  530.    {if(!son.lval)errore("lvalue expected");}
  531. else
  532.    ForceRvalue(&son);
  533. /* if(op=='+') in C non c'
  534.    ForceRvalue(&son);
  535. else
  536. */
  537. if(op=='-')
  538.    if(isimr(son)){
  539.       word t=this.symplus;
  540.       this.symplus=this.symminus;
  541.       this.symminus=t;
  542.       son.eval=-son.eval;
  543.       }
  544.    else{
  545.       ForceA(&son);Emit("NEG");}
  546. else if(op=='~')
  547.    if(son.class==immediate)
  548.       son.eval=~son.eval;
  549.    else{
  550.       ForceA(&son);Emit("NOT");}
  551. else if(op=='&'){
  552.    if(issimple(son))
  553.       if(son.class&1)
  554.          son.class--;
  555.       else if(son.sTable->typ==ass){
  556.          this.class=relocatable;
  557.          this.symplus=(word)(TOWORD(son.sTable));
  558.          this.eval=son.displacement;
  559.          this.symminus=0;
  560.          }
  561.       else{   /* dyn */
  562.          ForceBased(&son);
  563.          this.class=generated;this.place=1;
  564.          }
  565.    else{  /* based */
  566.       if(this.displacement!=0)
  567.          Emit("LEA %e",&son);
  568.       this.class=generated;this.place=1;
  569.       }
  570.    this.lval=0;
  571.    }
  572. else if(op=='*'){
  573.    if(isimsim(son)){  /*immediate,simplevar*/
  574.       if(son.class!=immediate)son.isCExpr=0;
  575.       son.class++;}
  576.    else if(son.class==relocatable&&son.symminus==0){
  577.       this.class=simplevar;this.displacement=son.eval;
  578.       {char*p=TOLONG(son.symplus);
  579.       this.sTable=((tabel*)p);}
  580.       }
  581.    else{
  582.       ForceX(&son);
  583.       this.class=based;this.displacement=0;
  584.       }
  585.    this.lval=1;
  586.    }
  587. else if(op=='!')
  588.    if(son.class==immediate)
  589.       this.eval=!son.eval;
  590.    else{
  591.       word t;
  592.       ForceFlags(&son);
  593.       son.condition ^=1; /* cio =INVERSE(son.condition) */
  594.       t=son.Flabel;
  595.       son.Flabel=son.Tlabel;
  596.       son.Tlabel=t;
  597.       }
  598. else{ /* ++ e -- */
  599.    ForceNative(&son);
  600.    Emit(op==0?"INC %e":"DEC %e",&son);
  601.    ForceRvalue(&son);
  602.    }
  603. }
  604. /****************/
  605. void UnaryPost(op,input)
  606. char op;
  607. {
  608. ForceNative(&this);
  609. if(!(input&externalCall)||token.asc!=';')
  610.    Emit("LOAD A,%e",&son);
  611. Emit(op==0?"INC %e":"DEC %e",&son);
  612. this.class=generated;
  613. this.lval=this.isCExpr=this.place=0;
  614. }
  615. /****************/
  616.  
  617.  
  618.  
  619. /* for binary operators, the parser calls two code generator routines in
  620. two places:
  621. ISO_... is called after the first operand, when the operator is known but
  622.     nothing is known about the second operand. "first" points to a
  623.     struct describing the left operand, which has also a few fields which
  624.     the code generator may use for its local variables
  625. BIN_... is called after the second operand, "first" points to the same
  626.     struct passed to ISO_..., the global variable "right" describes
  627.     the right operand, and the result of the operation must be stored
  628.     int "this" (physically overlayed with "right")
  629. For unary operators there is only one call (in theory there could be
  630. two calls for prefix operators, but no operator had anything which needed
  631. to be done before the operand)
  632. Also the ternary operator and the parameter passing are transformed into 
  633. a binary parse tree, but BIN_... may be called many times after a single ISO_...
  634.  
  635. */
  636.  
  637. #if NOT_OPTIMIZING
  638.  
  639. /* not optimazed versions: don't try to read any of the
  640. optimazing routines without understanding the general
  641. rules followed by the non-optimazing routines */
  642.  
  643. /*  non-optimizing version NON OPERATIVO */
  644. hidden char* opCode(op)
  645. char op;
  646. {
  647. static char
  648. tab[]={'+','-','|','&','^'};
  649. static char tab1[]=
  650.    "ADD\0SUB\0OR\0\0AND\0XOR\0ERROR";
  651.  i=0;
  652. while(tab[i]!=op&&i<5) i++;
  653. return &tab1[i<<2];
  654. }
  655.  
  656. hidden void ISO_plusminus(first)
  657. localmem*first;
  658. {
  659. /* semplificato, senza ottimizzazioni... */
  660. ForceStack(&left);
  661. }
  662. hidden void BIN_plusminus(first)
  663. localmem*first;
  664. {
  665. ForceA(&right);
  666. if(left.op=='-')
  667.    {Emit("NEG");left.op='+';}
  668. /* else if(op non commutativo)
  669.    Emit("EXC A,(SP)"); */
  670. Emit("%s (SP)+",opCode(left.op));
  671. }
  672.  
  673. /*******************/
  674. /* non-optimizing version NON OPERATIVO */
  675. hidden void ISO_andOr(first)
  676. localmem*first;
  677. {
  678. ForceJump(&left,left.op);
  679. }
  680. hidden void BIN_andOr(first)
  681. localmem*first;
  682. {
  683. ForceFlags(&right);
  684. if(right.label[left.op]==0)
  685.    right.label[left.op]=left.label[left.op];
  686. else
  687.    EQUforward(left.label[left.op],right.label[left.op]);
  688. }
  689. /*******************/
  690. /* non-optimizing version NON OPERATIVO */
  691. hidden void ISO_ternary(first)
  692. localmem*first;
  693. {ForceJump(&left,0);
  694. }
  695. hidden void BIN_1ternary(first)
  696. localmem*first;
  697. {
  698. ForceA(&right);
  699. BEmit(T,left.auxlabel=newlabel());
  700. LEmit(left.Flabel);
  701. }
  702. hidden void BIN_2ternary(first)
  703. localmem*first;
  704. {ForceA(&right);
  705. LEmit(left.auxlabel);
  706. }
  707. #endif /* NOT_OPTIMAZING */
  708.  
  709.  
  710.  
  711. hidden void ISO_assign(first)
  712. localmem*first;
  713. {if(left.class==based)
  714.    LazyPUSH(1);
  715. }
  716. hidden void BIN_assign(first)
  717. localmem*first;
  718. {char *p;
  719.  
  720. if(usesX(right)) /* *simplevar,based o generated */
  721.    ForceA(&right);
  722. if(left.class==based)
  723.    LazyPOP(1);
  724. if(right.class==immediate&&right.eval==0)
  725.    p="CLR";
  726. else
  727.    {ForceA(&right); p="STORE"; }
  728. ForceNative(&left);
  729. Emit("%s %e",p,&left);
  730. this.isCExpr=0;
  731. }
  732. /*******************/
  733. hidden GestioneReloc(first)
  734. localmem*first;
  735. {
  736. if(left.class==immediate){
  737.    left.symplus=left.symminus=0;
  738.    left.class=relocatable;}
  739. if(right.class==immediate){
  740.    right.symplus=right.symminus=0;
  741.    right.class=relocatable;}
  742. if(left.op=='-'){
  743.    word t=right.symplus;
  744.    right.symplus=right.symminus;
  745.    right.symminus=t;
  746.    right.eval=-right.eval;
  747.    left.op='+';
  748.    }
  749. if(left.symplus==right.symminus){
  750.    left.symplus=right.symminus=0;}
  751. if(right.symplus==left.symminus){
  752.    right.symplus=left.symminus=0;}
  753. if(right.symplus==0){
  754.    right.symplus=left.symplus;
  755.    left.symplus=0;}
  756. if(right.symminus==0){
  757.    right.symminus=left.symminus;
  758.    left.symminus=0;}
  759.  
  760. if(left.symplus==0&&left.symminus==0){
  761.    right.eval+=left.eval;
  762.    if(right.symplus==0&&right.symminus==0)
  763.       right.class=immediate;
  764.    return 1; /* ce l'ho fatta */
  765.    }
  766. return 0; /* la somma resta a run time */
  767. }
  768. /******************/
  769. hidden void GenOp(op,expr)
  770. char op;
  771. localmem*expr;
  772. {
  773. static char
  774. tab[]={'+','-','|','&','^'};
  775. static char tab1[]=
  776.    "ADD\0SUB\0OR\0\0AND\0XOR\0ERROR";
  777. char*p;
  778. int i=0;
  779. long labs();
  780.  
  781. while(tab[i]!=op&&i<5)i++;
  782. p=&tab1[i<<2];
  783. if(!expr)
  784.    Emit("%s (SP)+",p);
  785. else if(expr->class!=immediate){
  786.    ForceNative(expr);
  787.    Emit("%s %e",p,expr);}
  788. else if(i!=3&&expr->eval==0||
  789.         i==3&&expr->eval==-1)
  790.    ;  /* elemento neutro: +0,&-1 etc. */
  791. else if(i<=1&&labs(expr->eval)<=1)
  792.    if(i==(expr->eval<0))
  793.       Emit("INC A");
  794.    else
  795.       Emit("DEC A");
  796. else
  797.    Emit("%s #%d",p,expr->eval);
  798. }
  799. /***************************/
  800. hidden void ISO_generic(first)
  801. localmem*first;
  802. {
  803. if(!islazy(left))ForceStack(&left);
  804. }
  805. hidden void BIN_plusminus(first)
  806. localmem*first;
  807. {
  808. if(isimr(left)&&isimr(right)){
  809.    if(left.class==immediate&&right.class==immediate)
  810.       switch(left.op){
  811.       case'+':this.eval+=left.eval;return;
  812.       case'-':this.eval=left.eval-right.eval;return;
  813.       case'|':this.eval|=left.eval;return;
  814.       case'&':this.eval&=left.eval;return;
  815.       case'^':this.eval^=left.eval;return;
  816.       }
  817.    if((left.op=='-'||left.op=='+')&&GestioneReloc(first)!=0)
  818.       return;
  819.    }
  820. if(right.class>=generated||
  821.    right.class==based&&left.class==simplevar+1)
  822.    ForceA(&right);
  823. if(left.class==generated)
  824.    if(right.class==generated){
  825.       if(left.op=='-')
  826.          Emit("NEG%nADD (SP)+");
  827.       else
  828.          GenOp(left.op,NULL);
  829.       }
  830.    else{   /* generated-lazy */
  831.       LazyPOP(0);
  832.       GenOp(left.op,&right);}
  833. else{  /* left==lazy */
  834.    ForceNative(&left);
  835.    if(right.class==generated){
  836.       if(left.op=='-')
  837.          {Emit("NEG");left.op='+';}
  838.       GenOp(left.op,&left);
  839.       }
  840.    else{  /* lazy-lazy */
  841.       if(left.op=='-'||left.class!=immediate){
  842.          ForceA(&left); GenOp(left.op,&right);}
  843.       else{
  844.          ForceA(&right);GenOp(left.op,&left);}
  845.       }
  846.    }
  847. this.class=generated;
  848. this.place=this.lval=this.isCExpr=0;
  849. }
  850. /******************/
  851. #define SWAPCOND(op) op<=3?op:11-op
  852. hidden void BIN_compare(first)
  853. localmem*first;
  854. {
  855. if(left.class==immediate&&right.class==immediate){
  856.    switch(left.op){
  857.    case NE:case EQ:
  858.       this.eval=left.eval==right.eval;break;
  859.    case GE:case LT:
  860.       this.eval=left.eval <right.eval;break;
  861.    case GT:case LE:
  862.       this.eval=left.eval<=right.eval;break;
  863.    }
  864.    if(left.op&1)this.eval^=1;
  865.    return;
  866.    }
  867. if(left.class==generated)
  868.    if(right.class>=generated){
  869.       ForceA(&right);
  870.       Emit("SUB (SP)+");
  871.       this.condition=SWAPCOND(left.op);
  872.       }
  873.    else{
  874.       LazyPOP(0);
  875.       if(right.class==immediate&&right.eval==0)
  876.          Emit("TEST A");
  877.       else
  878.          GenOp('-',&right);
  879.       this.condition=left.op;
  880.       }
  881. else  /* left==lazy */
  882.    if(right.class==immediate){
  883.       if(right.eval==0){
  884.          ForceNative(&left);
  885.          Emit("TEST %e",&left);}
  886.       else{
  887.          ForceA(&left);
  888.          GenOp('-',&right);
  889.          }
  890.       this.condition=left.op;
  891.       }
  892.    else{
  893.       if(left.class==immediate&&left.eval==0){
  894.          ForceNative(&right);
  895.          Emit("TEST %e",&right);}
  896.       else{
  897.          ForceA(&right);
  898.          GenOp('-',&left);
  899.          }
  900.       this.condition=SWAPCOND(left.op);
  901.       }
  902. this.class=flags;
  903. this.Tlabel=this.Flabel=0;
  904. this.isCExpr=0;
  905. }
  906. /*******************/
  907. hidden void ISO_offset(first)
  908. localmem*first;
  909. {
  910. if(left.lval==0){
  911.    if(!islazy(left))
  912.       ForceStack(&left);
  913.    else if(left.class==immediate){
  914.       left.lval=1;left.class=immediate+1;}
  915.    }
  916. else
  917.    if(left.class==based)LazyPUSH(1);
  918. }
  919. hidden void BIN_offset(first)
  920. localmem*first;
  921. {
  922. if(left.lval){
  923.    if(usesX(right))ForceA(&right);
  924.    if(left.class==based)LazyPOP(1);
  925.    if(right.class==immediate){
  926.       if(left.class==immediate+1){
  927.          this.eval+=left.eval;
  928.          this.class=immediate+1;}
  929.       else{
  930.          ForceNative(&left);
  931.          this.displacement=left.displacement+right.eval;
  932.          this.class=left.class;
  933.          this.sTable=left.sTable; /* serve solo se simplevar */
  934.          }
  935.       }
  936.    else{
  937.       ForceBased(&left);
  938.       if(!islazy(right))ForceA(&right);
  939.       Emit("ADDX %e",&right);
  940.       this.class=based;
  941.       this.displacement=left.displacement;
  942.       this.isCExpr=0;
  943.       }
  944.    }
  945. else{  /* rvalue */
  946.    if(left.class==relocatable&&right.class==immediate){
  947.       left.eval+=right.eval;
  948.       ForceX(&left);
  949.       this.class=based;this.displacement=0;
  950.       }
  951.    else{
  952.       if(usesX(right))ForceA(&right);
  953.       if(!islazy(left))
  954.          LazyPOP(1);
  955.       else
  956.          ForceX(&left);
  957.       if(!islazy(right))ForceA(&right);
  958.       if(right.class!=immediate){
  959.          Emit("ADDX %e",&right);
  960.          this.displacement=0;
  961.          }
  962.       else
  963.          this.displacement=right.eval;
  964.       this.class=based;
  965.       }
  966.    this.isCExpr=0;
  967.    }
  968. this.lval=1;
  969. }
  970. /*******************************/
  971.  
  972.  
  973. /* there are TWO ways to pass parameters on the stack:
  974. Pushing first the first parameter
  975. Pushing first the LAST parameter
  976. The second way is necessary to implement the functions with a variable
  977. number of parameters of C (e.g. printf), the first one is simpler, 
  978. hence it's used when there is no printf to implement
  979. Note: this routines were written on a QL, not on the Mac. The C-like
  980. parameter passing method implemented is compatble with C compilers
  981. on the Mac, but the Pascal-like method does not account another
  982. feature of Pascal compilers for the Mac (and the Toolbox in ROM),
  983. which pass the return value on the stack rather than in a register
  984. (really, on paper I wrote the MC68000 equivalents of the
  985. abstract-accumulator-machine instructions which are generated by
  986. this program, but I never found the time to type them)
  987. */
  988.  
  989.  
  990. /* Di questa routine ne esistono due
  991. versioni, che pongono i parametri
  992. sullo stack in ordine diretto o
  993. inverso: c'Å bisogno anche di un
  994. parser leggermente diverso e la
  995. word parsInverted lo seleziona */
  996.  
  997. /* PRIMO PARAMETRO PRIMO SULLO STACK 
  998.    (come nel C della GST) (as in Macintosh Pascal, but the 
  999.                return value is in accumulator)
  1000. */
  1001. word parsInverted=0;
  1002.  
  1003. hidden void ISO_funCall(first)
  1004. localmem*first;
  1005. {
  1006. if(islazy(left))
  1007.    left.counter=0;
  1008. else{
  1009.    ForceStack(&left);
  1010.    left.counter=2;
  1011.    }
  1012. }
  1013. #define ISO_funpar null
  1014. hidden void BIN_funpar(first)
  1015. localmem*first;
  1016. {
  1017. ForceStack(&right);
  1018. left.counter+=2;
  1019. }
  1020. hidden void BIN_funCall(first)
  1021. localmem*first;
  1022. {
  1023.  
  1024. if(left.class==simplevar&&left.sTable->typ==ass||
  1025.    left.class==immediate){
  1026.    if(left.class==immediate)
  1027.       left.class=immediate+1;
  1028.    Emit("CALL %e",&left);
  1029.    }
  1030. else{
  1031.    if(!islazy(left)){
  1032.       if(left.counter==2)
  1033.          { LazyPOP(1);left.counter=0;}
  1034.       else
  1035.          Emit("LOAD X,%d(SP)",(long)left.counter-2);
  1036.       }
  1037.    else
  1038.       ForceX(&left);
  1039.    Emit("CALL (X)");
  1040.    }
  1041. if(left.counter!=0)Emit("ADD SP,#%d",(long)left.counter);
  1042. this.class=generated;
  1043. this.lval=this.place=this.isCExpr=0;
  1044. }
  1045. /* */
  1046. /***********************/
  1047. /* ULTIMO PARAMETRO PRIMO SULLO STACK (as in Macintosh Think C)
  1048.    (come nel C MetaComco) */
  1049.  
  1050. static word parOffset,parLname;
  1051.  
  1052. hidden word newlname()
  1053. {static word lastName=0;
  1054. return ++lastName;
  1055. }
  1056. void QEmit(lab,val)
  1057. word lab,val;
  1058. {
  1059. if(lastWasLabel){
  1060.    fprintf(out,"\n");lastWasLabel=0;}
  1061. fprintf(out,"C%d%sEQU %d\n",lab,lab<=9?"  ":" ",val);
  1062. }
  1063. hidden void ISO_funCall_inv(first)
  1064. localmem*first;
  1065. {
  1066. if(!islazy(left))ForceStack(&left);
  1067. left.counter=parOffset;parOffset=0;
  1068. left.auxLname=parLname;parLname=0;
  1069. }
  1070. hidden void ISO_funpar_inv(first)
  1071. localmem*first;
  1072. {
  1073. if(parLname==0)
  1074.    if(islazy(left))
  1075.       ;
  1076.    else if(token.asc==')'){    /* Wow,per un pelo ! */
  1077.       ForceStack(&left);
  1078.       parOffset=2;
  1079.       }
  1080.    else{ /* devo usare il modo costoso */
  1081.       Emit("SUB SP,#C%d",(long)(parLname=newlname()));
  1082.       ForceStack(&left);
  1083.       parOffset=2;
  1084.       }
  1085. else{
  1086.    ForceA(&left);
  1087.    Emit("STORE %d(SP)",(long)parOffset);
  1088.    parOffset+=2;
  1089.    }
  1090. }
  1091. hidden void BIN_funpar_inv(first)
  1092. localmem*first;
  1093. {
  1094. if(!islazy(left))return;
  1095. if(parLname!=0){
  1096.    QEmit(parLname,parOffset-2);
  1097.    parLname=0;
  1098.    }
  1099. ForceStack(&left);
  1100. parOffset+=2;
  1101. }
  1102. hidden void BIN_funCall_inv(first)
  1103. localmem*first;
  1104. {
  1105. if(parLname!=0)
  1106.    QEmit(parLname,parOffset-2);
  1107. if(!islazy(left))parOffset+=2;
  1108. if(left.class==simplevar&&left.sTable->typ==ass||
  1109.    left.class==immediate){
  1110.    if(left.class==immediate)
  1111.       left.class=immediate+1;
  1112.    Emit("CALL %e",&left);
  1113.    }
  1114. else{
  1115.    if(!islazy(left)){
  1116.       if(parOffset==2)
  1117.          { LazyPOP(1);parOffset=0;}
  1118.       else
  1119.          Emit("LOAD X,%d(SP)",(long)parOffset-2);
  1120.       }
  1121.    else
  1122.       ForceX(&left);
  1123.    Emit("CALL (X)");
  1124.    }
  1125. if(parOffset!=0)Emit("ADD SP,#%d",(long)parOffset);
  1126. this.class=generated;
  1127. this.lval=this.place=this.isCExpr=0;
  1128. parOffset=left.counter;parLname=left.auxLname;
  1129. }
  1130.  
  1131. /***********************************/
  1132. hidden int power2(val)
  1133. long val;
  1134. {int i;
  1135. if(val<=0)return -1;
  1136. for(i=0;!(val&1);val>>=1)i++;
  1137. if(val==1)return i;
  1138. else return -1;
  1139. }
  1140.  
  1141. hidden void GenMDS(op,expr)
  1142. char op;
  1143. localmem*expr;
  1144. {
  1145. static char tab[]={'*','/','%',0,1},
  1146.    *tab1[]={"MULT","DIV","MOD","LSHIFT","RSHIFT"},
  1147.    tab2[]="ASL\0ASR";
  1148. int i,j;
  1149. long val;
  1150. for(i=0;tab[i]!=op&&i<5;i++) ;
  1151. if(expr==NULL)
  1152.    {Emit("CALL %s",tab1[i]);
  1153.    return;}
  1154. val=expr->eval;
  1155. if(i<=1){  /* * e / */
  1156.    if(val==1)
  1157.       return;
  1158.    else if((j=power2(val))>=0){
  1159.       i+=3;val=j;}
  1160.    else if(i==0){
  1161.       if(val<0&&(j=power2(-val))>=0){
  1162.          Emit("NEG");
  1163.          i=3;val=j;}
  1164.       else if(val==0)
  1165.          {Emit("CLR A");return;}
  1166.       else if(val==3){
  1167.          Emit("PUSH A%nADD a%nADD (SP)+");
  1168.          return;}
  1169.       }
  1170.    }
  1171. if(i==2){  /* MOD */
  1172.    if((j=power2(val))>=0)
  1173.       {Emit("AND #%d",~(~(long)0<<j));
  1174.       return;}
  1175.    }
  1176. else if(i>=3){
  1177.    if(val<0){
  1178.       val=-val;i=7-i;}
  1179.    if(val<=3){
  1180.       while(--val>=0)
  1181.          Emit(&tab2[-12+(i<<2)]);
  1182.       return;}
  1183.    }
  1184. Emit("PUSH A%nLOAD A,#%d%nCALL %s",val,tab1[i]);
  1185. }
  1186. /*******************/
  1187. hidden void ISO_multdiv(first)
  1188. localmem*first;
  1189. {if(left.class!=immediate)ForceStack(&left);
  1190. }
  1191. hidden void BIN_multdiv(first)
  1192. localmem*first;
  1193. {
  1194. if(left.class==immediate)
  1195.    if(right.class==immediate)
  1196.       switch(left.op){
  1197.       case'*':this.eval*=left.eval;return;
  1198.       case'/':this.eval=left.eval/right.eval;return;
  1199.       case'%':this.eval=left.eval%right.eval;return;
  1200.       case 0 :this.eval=left.eval<<right.eval;return;
  1201.       case 1 :this.eval=left.eval>>right.eval;return;
  1202.       }
  1203.    else if(left.op=='*'){
  1204.       ForceA(&right);
  1205.       GenMDS('*',&left);}
  1206.    else{
  1207.       ForceA(&right);
  1208.       Emit("LOAD X,#%d%nPUSH X",left.eval);
  1209.       GenMDS(left.op,NULL);
  1210.       }
  1211. else
  1212.    if(right.class==immediate){
  1213.       LazyPOP(0);
  1214.       GenMDS(left.op,&right);
  1215.       }
  1216.    else{
  1217.       ForceA(&right);
  1218.       GenMDS(left.op,NULL);
  1219.       }
  1220. this.class=generated;
  1221. this.place=this.isCExpr=0;
  1222. }
  1223.  
  1224. /******************************/
  1225. hidden void ISO_andOr(first)
  1226. localmem*first;
  1227. {
  1228. if(left.class!=immediate)
  1229.    ForceJump(&left,left.op);
  1230. else{
  1231.    if(left.eval!=0)left.eval=1;
  1232.    if(left.eval==left.op)
  1233.       LazyJMP(&left);
  1234.    }
  1235. }
  1236. hidden void BIN_andOr(first)
  1237. localmem*first;
  1238. {
  1239. if(left.class==immediate)
  1240.    if(left.eval==left.op){ /* 0&& oppure 1|| */
  1241.       LazyLabel(&left);SuppressLabels(&right);
  1242.       this.eval=left.eval;this.class=immediate;
  1243.       }
  1244.    else{
  1245.       left.eval=0;left.op=NE;
  1246.       BIN_compare(&left);
  1247.       }
  1248. else{
  1249.    ForceFlags(&right);
  1250.    if(right.label[left.op]==0)
  1251.       right.label[left.op]=left.label[left.op];
  1252.    else
  1253.       EQUforward(left.label[left.op],right.label[left.op]);
  1254.    }
  1255. }
  1256. /*******************/
  1257. hidden void ISO_ternary(first)
  1258. localmem*first;
  1259. {
  1260. if(left.class!=immediate)
  1261.    ForceJump(&left,0);
  1262. else if(left.eval==0)
  1263.    LazyJMP(&left);
  1264. else
  1265.    left.eval=1;
  1266. }
  1267. hidden void BIN_1ternary(first)
  1268. localmem*first;
  1269. {
  1270. if(left.class!=immediate){
  1271.    ForceA(&right);
  1272.    BEmit(T,left.auxlabel=newlabel());
  1273.    LEmit(left.Flabel);
  1274.    left.auxternary=0xFF;
  1275.    }
  1276. else{
  1277.    byte b=left.eval;
  1278.    right.isCExpr&=left.isCExpr;
  1279.    movmem(&right.gci,&left.gci,sizeof(struct GCI));
  1280.    if((left.auxternary=b)==0){
  1281.       LazyLabel(&left);SuppressLabels(&right);
  1282.       }
  1283.    else
  1284.       LazyJMP(&left);
  1285.    }
  1286. }
  1287. hidden void BIN_2ternary(first)
  1288. localmem*first;
  1289. {
  1290. if(left.auxternary==0xFF){
  1291.    ForceA(&right);
  1292.    LEmit(left.auxlabel);
  1293.    }
  1294. else if(left.auxternary!=0){
  1295.    LazyLabel(&left);SuppressLabels(&right);
  1296.    left.isCExpr&=right.isCExpr;
  1297.    movmem(&left.gci,&right.gci,sizeof(struct GCI));
  1298.    }
  1299. }
  1300. /*******************/
  1301. #define ISO_comma SuppressLabels
  1302. #define BIN_comma null
  1303.  
  1304. /*******************/
  1305. void null(){}
  1306. static void (*ISOjmpTab[])()={
  1307. ISO_comma,ISO_generic,ISO_andOr,
  1308. ISO_generic,ISO_multdiv,
  1309. null,ISO_ternary,ISO_funpar,
  1310. ISO_funCall,ISO_offset,ISO_assign,
  1311. ISO_funpar_inv,ISO_funCall_inv};
  1312. static void (*BINjmpTab[])()={
  1313. BIN_comma,BIN_compare,BIN_andOr,
  1314. BIN_plusminus,BIN_multdiv,
  1315. BIN_1ternary,BIN_2ternary,BIN_funpar,
  1316. BIN_funCall,BIN_offset,BIN_assign,
  1317. BIN_funpar_inv,BIN_funCall_inv};
  1318.  
  1319. /**********************/
  1320. void InitSecOp(first,i)
  1321. localmem *first;
  1322. {
  1323.  
  1324. movmem(&(currentExpr.gci),&(first->gci),
  1325. sizeof(struct GCI));
  1326. if(!(first->opfea&32))
  1327.    if(first->opfea&lval1op)
  1328.       {if(!first->lval)errore("lvalue expected");}
  1329.    else
  1330.       ForceRvalue(first);
  1331. if(first->opfea&assignOp){
  1332.    ForceNative(first);
  1333.    ISO_assign(first);
  1334.    first->counter=first->class; /* dirty !! */
  1335.    }
  1336. (*ISOjmpTab[i])(first);
  1337. }
  1338. /********************/
  1339. void BinaryOp(first,i)
  1340. localmem*first;
  1341. {
  1342. if(!(first->opfea&32))ForceRvalue(&this);
  1343. (*BINjmpTab[i])(first);
  1344. if(first->opfea&assignOp){
  1345.    first->class=first->counter;
  1346.    BIN_assign(first);
  1347.    }
  1348. this.isCExpr&=left.isCExpr;
  1349. }
  1350.