home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Guide / c-cplusplus-interactive-guide.iso / c_ref / csource4 / 242_01 / a51eval.c < prev    next >
Text File  |  1989-01-13  |  11KB  |  456 lines

  1. /*
  2.     HEADER:        CUG242;
  3.     TITLE:        8051 Cross-Assembler (Portable);
  4.     FILENAME:    A51EVAL.C;
  5.     VERSION:    0.4;
  6.     DATE:        11/09/1988;
  7.     SEE-ALSO:    A51.H;
  8.     AUTHORS:    William C. Colley III;
  9. */
  10.  
  11. /*
  12.               8051 Cross-Assembler in Portable C
  13.  
  14.         Copyright (c) 1985,1987 William C. Colley, III
  15.  
  16. Revision History:
  17.  
  18. Ver    Date        Description
  19.  
  20. 0.0    JUL 1987    Adapted from version 0.0 of my portable 8048 cross-
  21.             assembler.  WCC3.
  22.  
  23. 0.1    OCT 1987    Changed the order of DW constants and made trailing
  24.             colons on labels get trashed.  WCC3.
  25.  
  26. 0.2    AUG 1988    Fixed bug that swapped the machine codes for CPL A and
  27.             CLR A.  WCC3.
  28.  
  29. 0.3    AUG 1988    Fixed a bug in the command line parser that puts it
  30.             into a VERY long loop if the user types a command line
  31.             like "A51 FILE.ASM -L".  WCC3 per Alex Cameron.
  32.  
  33. 0.4    NOV 1988    Fixed a bug that made DJNZ direct,relative generate
  34.             the wrong opcode.  WCC3.
  35.  
  36. This file contains the assembler's expression evaluator and lexical analyzer.
  37. The lexical analyzer chops the input character stream up into discrete tokens
  38. that are processed by the expression analyzer and the line assembler.  The
  39. expression analyzer processes the token stream into unsigned results of
  40. arithmetic expressions.
  41. */
  42.  
  43. /*  Get global goodies:  */
  44.  
  45. #include "a51.h"
  46.  
  47. /*  Get access to global mailboxes defined in A51.C:            */
  48.  
  49. extern char line[];
  50. extern int filesp, forwd, pass;
  51. extern unsigned pc;
  52. extern FILE *filestk[], *source;
  53. extern TOKEN token;
  54.  
  55. /*  Special expression analysis routine for fetching bit addresses.    */
  56.  
  57. unsigned bit_expr()
  58. {
  59.     SCRATCH unsigned u, v;
  60.     unsigned expr();
  61.     TOKEN *lex();
  62.     void error(), unlex();
  63.     
  64.     if ((lex() -> attr & TYPE) == BVAL) { u = token.valu;  lex();  return u; }
  65.     unlex();  u = expr();
  66.     if ((token.attr & TYPE) != DOT) {
  67.     if (u <= 0xff) return u;
  68.     }
  69.     else if ((v = expr()) <= 7) {
  70.     if (u >= 0x20 && u <= 0x2f) return low((u << 3) + v);
  71.     else if (u >= 0x80 && !(u & 0x07) && u <= 0xff) return u + v;
  72.     }
  73.     error('V');  return 0;
  74. }
  75.  
  76. /*  Expression analysis routine.  The token stream from the lexical    */
  77. /*  analyzer is processed as an arithmetic expression and reduced to an    */
  78. /*  unsigned value.  If an error occurs during the evaluation, the    */
  79. /*  global flag    forwd is set to indicate to the line assembler that it    */
  80. /*  should not base certain decisions on the result of the evaluation.    */
  81.  
  82. static int bad;
  83.  
  84. unsigned expr()
  85. {
  86.     SCRATCH unsigned u;
  87.     unsigned eval();
  88.  
  89.     bad = FALSE;
  90.     u = eval(START);
  91.     return bad ? 0 : u;
  92. }
  93.  
  94. static unsigned eval(pre)
  95. unsigned pre;
  96. {
  97.     register unsigned op, u, v;
  98.     TOKEN *lex();
  99.     void exp_error(), unlex();
  100.  
  101.     for (;;) {
  102.     u = op = lex() -> valu;
  103.     switch (token.attr & TYPE) {
  104.         default:    if (pre != START) unlex();
  105.         case EOL:    exp_error('E');  return;
  106.  
  107.         case OPR:    if (!(token.attr & UNARY)) { exp_error('E');  break; }
  108.             u = (op == '$' ? pc :
  109.                 eval((op == '+' || op == '-') ?
  110.                 (unsigned) UOP1 : token.attr & PREC));
  111.             switch (op) {
  112.                 case '-':    u = word(-u);  break;
  113.  
  114.                 case NOT:    u ^= 0xffff;  break;
  115.  
  116.                 case HIGH:    u = high(u);  break;
  117.  
  118.                 case LOW:    u = low(u);  break;
  119.             }
  120.  
  121.         case VAL:    
  122.         case STR:    for (;;) {
  123.                 op = lex() -> valu;
  124.                 switch (token.attr & TYPE) {
  125.                 default:   if (pre != START) unlex();
  126.                 case EOL:   if (pre == LPREN) exp_error('(');
  127.                         return u;
  128.  
  129.                 case STR:
  130.                 case VAL:   exp_error('E');  break;
  131.  
  132.                 case OPR:   if (!(token.attr & BINARY)) {
  133.                         exp_error('E');  break;
  134.                         }
  135.                         if ((token.attr & PREC) >= pre) {
  136.                         unlex();  return u;
  137.                         }
  138.                         if (op != ')')
  139.                         v = eval(token.attr & PREC);
  140.                         switch (op) {
  141.                         case '+':   u += v;  break;
  142.  
  143.                         case '-':   u -= v;  break;
  144.  
  145.                         case '*':   u *= v;  break;
  146.  
  147.                         case '/':   u /= v;  break;
  148.  
  149.                         case MOD:   u %= v;  break;
  150.  
  151.                         case AND:   u &= v;  break;
  152.  
  153.                         case OR:    u |= v;  break;
  154.  
  155.                         case XOR:   u ^= v;  break;
  156.  
  157.                         case '<':   u = u < v;  break;
  158.  
  159.                         case LE:    u = u <= v;  break;
  160.  
  161.                         case '=':   u = u == v;  break;
  162.  
  163.                         case GE:    u = u >= v;  break;
  164.  
  165.                         case '>':   u = u > v;  break;
  166.  
  167.                         case NE:    u = u != v;  break;
  168.  
  169.                         case SHL:   if (v > 15)
  170.                                 exp_error('E');
  171.                                 else u <<= v;
  172.                                 break;
  173.  
  174.                         case SHR:   if (v > 15)
  175.                                 exp_error('E');
  176.                                 else u >>= v;
  177.                                 break;
  178.  
  179.                         case ')':   if (pre == LPREN)
  180.                                 return u;
  181.                                 exp_error('(');
  182.                                 break;
  183.                         }
  184.                         clamp(u);
  185.                         break;
  186.                 }
  187.             }
  188.             break;
  189.     }
  190.     }
  191. }
  192.  
  193. static void exp_error(c)
  194. char c;
  195. {
  196.     void error();
  197.  
  198.     forwd = bad = TRUE;  error(c);
  199. }
  200.  
  201. /*  Lexical analyzer.  The source input character stream is chopped up    */
  202. /*  into its component parts and the pieces are evaluated.  Symbols are    */
  203. /*  looked up, operators are looked up, etc.  Everything gets reduced    */
  204. /*  to an attribute word, a numeric value, and (possibly) a string    */
  205. /*  value.                                */
  206.  
  207. static int oldt = FALSE;
  208. static int quote = FALSE;
  209.  
  210. TOKEN *lex()
  211. {
  212.     SCRATCH char c, *p;
  213.     SCRATCH unsigned b;
  214.     SCRATCH OPCODE *o;
  215.     SCRATCH SYMBOL *s;
  216.     OPCODE *find_operator();
  217.     SYMBOL *find_symbol();
  218.     void exp_error(), make_number(), pops(), pushc(), trash();
  219.  
  220.     if (oldt) { oldt = FALSE;  return &token; }
  221.     trash();
  222.     if (isalph(c = popc())) {
  223.     pushc(c);  pops(token.sval);
  224.     if (o = find_operator(token.sval)) {
  225.         token.attr = o -> attr;
  226.         token.valu = o -> valu;
  227.     }
  228.     else {
  229.         token.attr = VAL;  token.valu = 0;
  230.         if (s = find_symbol(token.sval)) {
  231.         token.attr = s -> attr;  token.valu = s -> valu;
  232.         if (pass == 2 && s -> attr & FORWD) forwd = TRUE;
  233.         }
  234.         else exp_error('U');
  235.     }
  236.     }
  237.     else if (isnum(c)) {
  238.     pushc(c);  pops(token.sval);
  239.     for (p = token.sval; *p; ++p);
  240.     switch (toupper(*--p)) {
  241.         case 'B':    b = 2;  break;
  242.  
  243.         case 'O':
  244.         case 'Q':    b = 8;  break;
  245.  
  246.         default:    ++p;
  247.         case 'D':    b = 10;  break;
  248.  
  249.         case 'H':    b = 16;  break;
  250.     }
  251.     *p = '\0';  make_number(b);
  252.     }
  253.     else switch (c) {
  254.     case '@':   if ((lex() -> attr & TYPE) != REG) exp_error('S');
  255.             else switch (token.valu) {
  256.             case A:     token.valu = AT_A;  break;
  257.  
  258.             case DPTR:  token.valu = AT_DPTR;  break;
  259.  
  260.             case R0:    token.valu = AT_R0;  break;
  261.  
  262.             case R1:    token.valu = AT_R1;  break;
  263.  
  264.             default:    exp_error('S');
  265.             }
  266.             break;
  267.  
  268.     case '#':   token.attr = IMM;  break;
  269.  
  270.     case '(':   token.attr = UNARY + LPREN + OPR;  goto opr1;
  271.  
  272.     case ')':   token.attr = BINARY + RPREN + OPR;  goto opr1;
  273.  
  274.     case '+':   token.attr = BINARY + UNARY + ADDIT + OPR;  goto opr1;
  275.  
  276.     case '-':   token.attr = BINARY + UNARY + ADDIT + OPR;  goto opr1;
  277.  
  278.     case '*':   token.attr = BINARY + MULT + OPR;  goto opr1;
  279.  
  280.     case '/':   token.attr = BINARY + MULT + OPR;
  281. opr1:            token.valu = c;  break;
  282.  
  283.     case '<':   token.valu = c;
  284.             if ((c = popc()) == '=') token.valu = LE;
  285.             else if (c == '>') token.valu = NE;
  286.             else pushc(c);
  287.             goto opr2;
  288.  
  289.     case '=':   token.valu = c;
  290.             if ((c = popc()) == '<') token.valu = LE;
  291.             else if (c == '>') token.valu = GE;
  292.             else pushc(c);
  293.             goto opr2;
  294.  
  295.     case '>':   token.valu = c;
  296.             if ((c = popc()) == '<') token.valu = NE;
  297.             else if (c == '=') token.valu = GE;
  298.             else pushc(c);
  299. opr2:            token.attr = BINARY + RELAT + OPR;  break;
  300.  
  301.     case '\'':
  302.     case '"':   quote = TRUE;  token.attr = STR;
  303.             for (p = token.sval; (*p = popc()) != c; ++p)
  304.             if (*p == '\n') { exp_error('"');  break; }
  305.             *p = '\0';  quote = FALSE;
  306.             if ((token.valu = token.sval[0]) && token.sval[1])
  307.             token.valu = (token.valu << 8) + token.sval[1];
  308.             break;
  309.  
  310.     case '.':   token.attr = DOT;  break;
  311.  
  312.     case ',':   token.attr = SEP;  break;
  313.  
  314.         case '\n':  token.attr = EOL;  break;
  315.     }
  316.     return &token;
  317. }
  318.  
  319. static void make_number(base)
  320. unsigned base;
  321. {
  322.     SCRATCH char *p;
  323.     SCRATCH unsigned d;
  324.     void exp_error();
  325.  
  326.