home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / misc / emu / AROSdev.lha / AROS / compiler / vcpp / lex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-10  |  14.8 KB  |  571 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "cpp.h"
  5.  
  6. /*
  7.  * lexical FSM encoding
  8.  *   when in state state, and one of the characters
  9.  *   in ch arrives, enter nextstate.
  10.  *   States >= S_SELF are either final, or at least require special action.
  11.  *   In 'fsm' there is a line for each state X charset X nextstate.
  12.  *   List chars that overwrite previous entries later (e.g. C_ALPH
  13.  *   can be overridden by '_' by a later entry; and C_XX is the
  14.  *   the universal set, and should always be first.
  15.  *   States above S_SELF are represented in the big table as negative values.
  16.  *   S_SELF and S_SELFB encode the resulting token type in the upper bits.
  17.  *   These actions differ in that S_SELF doesn't have a lookahead char,
  18.  *   S_SELFB does.
  19.  *
  20.  *   The encoding is blown out into a big table for time-efficiency.
  21.  *   Entries have
  22.  *    nextstate: 6 bits; ?\ marker: 1 bit; tokentype: 9 bits.
  23.  */
  24.  
  25. #define MAXSTATE 32
  26. #define ACT(tok,act)    ((tok<<7)+act)
  27. #define QBSBIT    0100
  28. #define GETACT(st)      (st>>7)&0x1ff
  29.  
  30. /* character classes */
  31. #define C_WS    1
  32. #define C_ALPH    2
  33. #define C_NUM    3
  34. #define C_EOF    4
  35. #define C_XX    5
  36.  
  37. enum state {
  38.     START=0, NUM1, NUM2, NUM3, ID1, ST1, ST2, ST3, COM1, COM2, COM3, COM4,
  39.     CC1, CC2, WS1, PLUS1, MINUS1, STAR1, SLASH1, PCT1, SHARP1,
  40.     CIRC1, GT1, GT2, LT1, LT2, OR1, AND1, ASG1, NOT1, DOTS1,
  41.     S_SELF=MAXSTATE, S_SELFB, S_EOF, S_NL, S_EOFSTR,
  42.     S_STNL, S_COMNL, S_EOFCOM, S_COMMENT, S_EOB, S_WS, S_NAME
  43. };
  44.  
  45. int    tottok;
  46. int    tokkind[256];
  47. struct    fsm {
  48.     int    state;        /* if in this state */
  49.     uchar    ch[4];        /* and see one of these characters */
  50.     int    nextstate;    /* enter this state if +ve */
  51. };
  52.  
  53. /*const*/ struct fsm fsm[] = {
  54.     /* start state */
  55.        { START,  { C_XX },     ACT(UNCLASS,S_SELF), },
  56.        { START,  { ' ', '\t', '\v' },    WS1,         },
  57.        { START,  { C_NUM },     NUM1,              },
  58.        { START,  { '.' },        NUM3,                },
  59.        { START,  { C_ALPH },     ID1,              },
  60.        { START,  { 'L' },        ST1,                 },
  61.        { START,  { '"' },        ST2,                 },
  62.        { START,  { '\'' },       CC1,                 },
  63.        { START,  { '/' },        COM1,                },
  64.        { START,  { EOFC },     S_EOF,           },
  65.        { START,  { '\n' },       S_NL,                },
  66.        { START,  { '-' },        MINUS1,              },
  67.        { START,  { '+' },        PLUS1,               },
  68.        { START,  { '<' },        LT1,                 },
  69.        { START,  { '>' },        GT1,                 },
  70.        { START,  { '=' },        ASG1,                },
  71.        { START,  { '!' },        NOT1,                },
  72.        { START,  { '&' },        AND1,                },
  73.        { START,  { '|' },        OR1,                 },
  74.        { START,  { '#' },        SHARP1,              },
  75.        { START,  { '%' },        PCT1,                },
  76.        { START,  { '[' },        ACT(SBRA,S_SELF),    },
  77.        { START,  { ']' },        ACT(SKET,S_SELF),    },
  78.        { START,  { '(' },        ACT(LP,S_SELF),      },
  79.        { START,  { ')' },        ACT(RP,S_SELF),      },
  80.        { START,  { '*' },        STAR1,               },
  81.        { START,  { ',' },        ACT(COMMA,S_SELF),   },
  82.        { START,  { '?' },        ACT(QUEST,S_SELF),   },
  83.        { START,  { ':' },        ACT(COLON,S_SELF),   },
  84.        { START,  { ';' },        ACT(SEMIC,S_SELF),   },
  85.        { START,  { '{' },        ACT(CBRA,S_SELF),    },
  86.        { START,  { '}' },        ACT(CKET,S_SELF),    },
  87.        { START,  { '~' },        ACT(TILDE,S_SELF),   },
  88.        { START,  { '^' },        CIRC1,               },
  89.  
  90.     /* saw a digit */
  91.        { NUM1,     { C_XX },     ACT(NUMBER,S_SELFB), },
  92.        { NUM1,     { C_NUM, C_ALPH, '.' }, NUM1,        },
  93.        { NUM1,     { 'E', 'e' },   NUM2,                },
  94.        { NUM1,     { '_' },        ACT(NUMBER,S_SELFB), },
  95.  
  96.     /* saw possible start of exponent, digits-e */
  97.        { NUM2,     { C_XX },     ACT(NUMBER,S_SELFB), },
  98.        { NUM2,     { '+', '-' },   NUM1,                },
  99.        { NUM2,     { C_NUM, C_ALPH },     NUM1,          },
  100.        { NUM2,     { '_' },        ACT(NUMBER,S_SELFB), },
  101.  
  102.     /* saw a '.', which could be a number or an operator */
  103.        { NUM3,     { C_XX },     ACT(DOT,S_SELFB),    },
  104.        { NUM3,     { '.' },        DOTS1,               },
  105.        { NUM3,     { C_NUM },     NUM1,              },
  106.  
  107.        { DOTS1,  { C_XX },     ACT(UNCLASS, S_SELFB), },
  108.        { DOTS1,  { C_NUM },     NUM1,              },
  109.        { DOTS1,  { '.' },        ACT(ELLIPS, S_SELF), },
  110.  
  111.     /* saw a letter or _ */
  112.        { ID1,     { C_XX },     ACT(NAME,S_NAME),    },
  113.        { ID1,     { C_ALPH, C_NUM },     ID1,          },
  114.  
  115.     /* saw L (start of wide string?) */
  116.        { ST1,     { C_XX },     ACT(NAME,S_NAME),    },
  117.        { ST1,     { C_ALPH, C_NUM },     ID1,          },
  118.        { ST1,     { '"' },        ST2,                 },
  119.        { ST1,     { '\'' },       CC1,                 },
  120.  
  121.     /* saw " beginning string */
  122.        { ST2,     { C_XX },     ST2,              },
  123.        { ST2,     { '"' },        ACT(STRING, S_SELF), },
  124.        { ST2,     { '\\' },       ST3,                 },
  125.        { ST2,     { '\n' },       S_STNL,              },
  126.        { ST2,     { EOFC },     S_EOFSTR,          },
  127.  
  128.     /* saw \ in string */
  129.        { ST3,     { C_XX },     ST2,              },
  130.        { ST3,     { '\n' },       S_STNL,              },
  131.        { ST3,     { EOFC },     S_EOFSTR,          },
  132.  
  133.     /* saw ' beginning character const */
  134.        { CC1,     { C_XX },     CC1,              },
  135.        { CC1,     { '\'' },       ACT(CCON, S_SELF),   },
  136.        { CC1,     { '\\' },       CC2,                 },
  137.        { CC1,     { '\n' },       S_STNL,              },
  138.        { CC1,     { EOFC },     S_EOFSTR,          },
  139.  
  140.     /* saw \ in ccon */
  141.        { CC2,     { C_XX },     CC1,              },
  142.        { CC2,     { '\n' },       S_STNL,              },
  143.        { CC2,     { EOFC },     S_EOFSTR,          },
  144.  
  145.     /* saw /, perhaps start of comment */
  146.        { COM1,     { C_XX },     ACT(SLASH, S_SELFB), },
  147.        { COM1,     { '=' },        ACT(ASSLASH, S_SELF),},
  148.        { COM1,     { '*' },        COM2,                },
  149.        { COM1,     { '/' },        COM4,                },
  150.  
  151.     /* saw '/' and '*' -> start of comment */
  152.        { COM2,     { C_XX },     COM2,              },
  153.        { COM2,     { '\n' },       S_COMNL,             },
  154.        { COM2,     { '*' },        COM3,                },
  155.        { COM2,     { EOFC },     S_EOFCOM,          },
  156.  
  157.     /* saw the * possibly ending a comment */
  158.        { COM3,     { C_XX },     COM2,              },
  159.        { COM3,     { '\n' },       S_COMNL,             },
  160.        { COM3,     { '*' },        COM3,                },
  161.        { COM3,     { '/' },        S_COMMENT,           },
  162.  
  163.     /* // comment */
  164.        { COM4,     { C_XX },     COM4,              },
  165.        { COM4,     { '\n' },       S_NL,                },
  166.        { COM4,     { EOFC },     S_EOFCOM,          },
  167.  
  168.     /* saw white space, eat it up */
  169.        { WS1,     { C_XX },     S_WS,              },
  170.        { WS1,     { ' ', '\t', '\v' },    WS1,         },
  171.  
  172.     /* saw -, check --, -=, -> */
  173.        { MINUS1, { C_XX },     ACT(MINUS, S_SELFB), },
  174.        { MINUS1, { '-' },        ACT(MMINUS, S_SELF), },
  175.        { MINUS1, { '=' },        ACT(ASMINUS,S_SELF), },
  176.        { MINUS1, { '>' },        ACT(ARROW,S_SELF),   },
  177.  
  178.     /* saw +, check ++, += */
  179.        { PLUS1,  { C_XX },     ACT(PLUS, S_SELFB),  },
  180.        { PLUS1,  { '+' },        ACT(PPLUS, S_SELF),  },
  181.        { PLUS1,  { '=' },        ACT(ASPLUS, S_SELF), },
  182.  
  183.     /* saw <, check <<, <<=, <= */
  184.        { LT1,     { C_XX },     ACT(LT, S_SELFB),    },
  185.        { LT1,     { '<' },        LT2,                 },
  186.        { LT1,     { '=' },        ACT(LEQ, S_SELF),    },
  187.        { LT2,     { C_XX },     ACT(LSH, S_SELFB),   },
  188.        { LT2,     { '=' },        ACT(ASLSH, S_SELF),  },
  189.  
  190.     /* saw >, check >>, >>=, >= */
  191.        { GT1,     { C_XX },     ACT(GT, S_SELFB),    },
  192.        { GT1,     { '>' },        GT2,                 },
  193.        { GT1,     { '=' },        ACT(GEQ, S_SELF),    },
  194.        { GT2,     { C_XX },     ACT(RSH, S_SELFB),   },
  195.        { GT2,     { '=' },        ACT(ASRSH, S_SELF),  },
  196.  
  197.     /* = */
  198.        { ASG1,     { C_XX },     ACT(ASGN, S_SELFB),  },
  199.        { ASG1,     { '=' },        ACT(EQ, S_SELF),     },
  200.  
  201.     /* ! */
  202.        { NOT1,     { C_XX },     ACT(NOT, S_SELFB),   },
  203.        { NOT1,     { '=' },        ACT(NEQ, S_SELF),    },
  204.  
  205.     /* & */
  206.        { AND1,     { C_XX },     ACT(AND, S_SELFB),   },
  207.        { AND1,     { '&' },        ACT(LAND, S_SELF),   },
  208.        { AND1,     { '=' },        ACT(ASAND, S_SELF),  },
  209.  
  210.     /* | */
  211.        { OR1,     { C_XX },     ACT(OR, S_SELFB),    },
  212.        { OR1,     { '|' },        ACT(LOR, S_SELF),    },
  213.        { OR1,     { '=' },        ACT(ASOR, S_SELF),   },
  214.  
  215.     /* # */
  216.        { SHARP1, { C_XX },     ACT(SHARP, S_SELFB), },
  217.        { SHARP1, { '#' },        ACT(DSHARP, S_SELF), },
  218.  
  219.     /* % */
  220.        { PCT1,     { C_XX },     ACT(PCT, S_SELFB),   },
  221.        { PCT1,     { '=' },        ACT(ASPCT, S_SELF),  },
  222.  
  223.     /* * */
  224.        { STAR1,  { C_XX },     ACT(STAR, S_SELFB),  },
  225.        { STAR1,  { '=' },        ACT(ASSTAR, S_SELF), },
  226.  
  227.     /* ^ */
  228.        { CIRC1,  { C_XX },     ACT(CIRC, S_SELFB),  },
  229.        { CIRC1,  { '=' },        ACT(ASCIRC, S_SELF), },
  230.  
  231.        { -1,                          }
  232. };
  233.  
  234. /* first index is char, second is state */
  235. /* increase #states to power of 2 to encourage use of shift */
  236. short    bigfsm[256][MAXSTATE];
  237.  
  238. void
  239. expandlex(void)
  240. {
  241.     /*const*/ struct fsm *fp;
  242.     int i, j, nstate;
  243.  
  244.     for (fp = fsm; fp->state>=0; fp++) {
  245.         for (i=0; fp->ch[i]; i++) {
  246.             nstate = fp->nextstate;
  247.             if (nstate >= S_SELF)
  248.                 nstate = ~nstate;
  249.             switch (fp->ch[i]) {
  250.  
  251.             case C_XX:        /* random characters */
  252.                 for (j=0; j<256; j++)
  253.                     bigfsm[j][fp->state] = nstate;
  254.                 continue;
  255.             case C_ALPH:
  256.                 for (j=0; j<=256; j++)
  257.                     if ('a'<=j&&j<='z' || 'A'<=j&&j<='Z'
  258.                       || j=='_')
  259.                         bigfsm[j][fp->state] = nstate;
  260.                 continue;
  261.             case C_NUM:
  262.                 for (j='0'; j<='9'; j++)
  263.                     bigfsm[j][fp->state] = nstate;
  264.                 continue;
  265.             default:
  266.                 bigfsm[fp->ch[i]][fp->state] = nstate;
  267.             }
  268.         }
  269.     }
  270.     /* install special cases for ? (trigraphs),  \ (splicing), runes, and EOB */
  271.     for (i=0; i<MAXSTATE; i++) {
  272.         for (j=0; j<0xFF; j++)
  273.             if (j=='?' || j=='\\') {
  274.                 if (bigfsm[j][i]>0)
  275.                     bigfsm[j][i] = ~bigfsm[j][i];
  276.                 bigfsm[j][i] &= ~QBSBIT;
  277.             }
  278.         bigfsm[EOB][i] = ~S_EOB;
  279.         if (bigfsm[EOFC][i]>=0)
  280.             bigfsm[EOFC][i] = ~S_EOF;
  281.     }
  282. }
  283.  
  284. void
  285. fixlex(void)
  286. {
  287.     /* do C++ comments? */
  288.     if (Cplusplus==0)
  289.         bigfsm['/'][COM1] = bigfsm['x'][COM1];
  290. }
  291.  
  292. /*
  293.  * fill in a row of tokens from input, terminated by NL or END
  294.  * First token is put at trp->lp.
  295.  * Reset is non-zero when the input buffer can be "rewound."
  296.  * The value is a flag indicating that possible macros have
  297.  * been seen in the row.
  298.  */
  299. int
  300. gettokens(Tokenrow *trp, int reset)
  301. {
  302.     register int c, state, oldstate;
  303.     register uchar *ip;
  304.     register Token *tp, *maxp;
  305.     int runelen;
  306.     Source *s = cursource;
  307.     int nmac = 0;
  308.  
  309.     tp = trp->lp;
  310.     ip = s->inp;
  311.     if (reset) {
  312.         s->lineinc = 0;
  313.         if (ip>=s->inl) {               /* nothing in buffer */
  314.             s->inl = s->inb;
  315.             fillbuf(s);
  316.             ip = s->inp = s->inb;
  317.         } else if (ip >= s->inb+(3*INS/4)) {
  318.             memmove(s->inb, ip, 4+s->inl-ip);
  319.             s->inl = s->inb+(s->inl-ip);
  320.             ip = s->inp = s->inb;
  321.         }
  322.     }
  323.     maxp = &trp->bp[trp->max];
  324.     runelen = 1;
  325.     for (;;) {
  326.        continue2:
  327.         if (tp>=maxp) {
  328.             trp->lp = tp;
  329.             tp = growtokenrow(trp);
  330.             maxp = &trp->bp[trp->max];
  331.         }
  332.         tp->type = UNCLASS;
  333.         tp->hideset = 0;
  334.         tp->t = ip;
  335.         tp->wslen = 0;
  336.         tp->flag = 0;
  337.         state = START;
  338.         for (;;) {
  339.             oldstate = state;
  340.             c = *ip;
  341.             if ((state = bigfsm[c][state]) >= 0) {
  342.                 ip += runelen;
  343.                 runelen = 1;
  344.                 continue;
  345.             }
  346.             state = ~state;
  347.         reswitch:
  348.             switch (state&0177) {
  349.             case S_SELF:
  350.                 ip += runelen;
  351.                 runelen = 1;
  352.             case S_SELFB:
  353.                 tp->type = GETACT(state);
  354.                 tp->len = ip - tp->t;
  355.                 tp++;
  356.                 goto continue2;
  357.  
  358.             case S_NAME:    /* like S_SELFB but with nmac check */
  359.                 tp->type = NAME;
  360.                 tp->len = ip - tp->t;
  361.                 nmac |= quicklook(tp->t[0], tp->len>1?tp->t[1]:0);
  362.                 tp++;
  363.                 goto continue2;
  364.  
  365.             case S_WS:
  366.                 tp->wslen = ip - tp->t;
  367.                 tp->t = ip;
  368.                 state = START;
  369.                 continue;
  370.  
  371.             default:
  372.                 if ((state&QBSBIT)==0) {
  373.                     ip += runelen;
  374.                     runelen = 1;
  375.                     continue;
  376.                 }
  377.                 state &= ~QBSBIT;
  378.                 s->inp = ip;
  379.                 if (c=='?') {   /* check trigraph */
  380.                     if (trigraph(s)) {
  381.                         state = oldstate;
  382.                         continue;
  383.                     }
  384.                     goto reswitch;
  385.                 }
  386.                 if (c=='\\') { /* line-folding */
  387.                     if (foldline(s)) {
  388.                         s->lineinc++;
  389.                         state = oldstate;
  390.                         continue;
  391.                     }
  392.                     goto reswitch;
  393.                 }
  394.                 error(WARNING, "Lexical botch in cpp");
  395.                 ip += runelen;
  396.                 runelen = 1;
  397.                 continue;
  398.  
  399.             case S_EOB:
  400.                 s->inp = ip;
  401.                 fillbuf(cursource);
  402.                 state = oldstate;
  403.                 continue;
  404.  
  405.             case S_EOF:
  406.                 tp->type = END;
  407.                 tp->len = 0;
  408.                 s->inp = ip;
  409.                 if (tp!=trp->bp && (tp-1)->type!=NL && cursource->fd!=-1)
  410.                     error(WARNING,"No newline at end of file");
  411.                 trp->lp = tp+1;
  412.                 return nmac;
  413.  
  414.             case S_STNL:
  415.                 error(ERROR, "Unterminated string or char const");
  416.             case S_NL:
  417.                 tp->t = ip;
  418.                 tp->type = NL;
  419.                 tp->len = 1;
  420.                 tp->wslen = 0;
  421.                 s->lineinc++;
  422.                 s->inp = ip+1;
  423.                 trp->lp = tp+1;
  424.                 return nmac;
  425.  
  426.             case S_EOFSTR:
  427.                 error(FATAL, "EOF in string or char constant");
  428.                 break;
  429.  
  430.             case S_COMNL:
  431.                 s->lineinc++;
  432.                 state = COM2;
  433.                 ip += runelen;
  434.                 runelen = 1;
  435.                 continue;
  436.  
  437.             case S_EOFCOM:
  438.                 error(WARNING, "EOF inside comment");
  439.                 --ip;
  440.             case S_COMMENT:
  441.                 ++ip;
  442.                 tp->t = ip;
  443.                 tp->t[-1] = ' ';
  444.                 tp->wslen = 1;
  445.                 state = START;
  446.                 continue;
  447.             }
  448.             break;
  449.         }
  450.         ip += runelen;
  451.         runelen = 1;
  452.         tp->len = ip - tp->t;
  453.         tp++;
  454.     }
  455. }
  456.  
  457. /* have seen ?; handle the trigraph it starts (if any) else 0 */
  458. int
  459. trigraph(Source *s)
  460. {
  461.     int c;
  462.  
  463.     while (s->inp+2 >= s->inl && fillbuf(s)!=EOF)
  464.         ;
  465.     if (s->inp[1]!='?')
  466.         return 0;
  467.     c = 0;
  468.     switch(s->inp[2]) {
  469.     case '=':
  470.         c = '#'; break;
  471.     case '(':
  472.         c = '['; break;
  473.     case '/':
  474.         c = '\\'; break;
  475.     case ')':
  476.         c = ']'; break;
  477.     case '\'':
  478.         c = '^'; break;
  479.     case '<':
  480.         c = '{'; break;
  481.     case '!':
  482.         c = '|'; break;
  483.     case '>':
  484.         c = '}'; break;
  485.     case '-':
  486.         c = '~'; break;
  487.     }
  488.     if (c) {
  489.         *s->inp = c;
  490.         memmove(s->inp+1, s->inp+3, s->inl-s->inp+2);
  491.         s->inl -= 2;
  492.     }
  493.     return c;
  494. }
  495.  
  496. int
  497. foldline(Source *s)
  498. {
  499.     while (s->inp+1 >= s->inl && fillbuf(s)!=EOF)
  500.         ;
  501.     if (s->inp[1] == '\n') {
  502.         memmove(s->inp, s->inp+2, s->inl-s->inp+3);
  503.         s->inl -= 2;
  504.         return 1;
  505.     }
  506.     return 0;
  507. }
  508.  
  509. int
  510. fillbuf(Source *s)
  511. {
  512.     int n;
  513.  
  514.     if (s->fd<0 || (n=read(s->fd, (char *)s->inl, INS/8)) <= 0)
  515.         n = 0;
  516.     s->inl += n;
  517.     s->inl[0] = s->inl[1]= s->inl[2]= s->inl[3] = EOB;
  518.     if (n==0) {
  519.         s->inl[0] = s->inl[1]= s->inl[2]= s->inl[3] = EOFC;
  520.         return EOF;
  521.     }
  522.     return 0;
  523. }
  524.  
  525. /*
  526.  * Push down to new source of characters.
  527.  * If fd>0 and str==NULL, then from a file `name';
  528.  * if fd==-1 and str, then from the string.
  529.  */
  530. Source *
  531. setsource(char *name, int fd, char *str)
  532. {
  533.     Source *s = new(Source);
  534.     int len;
  535.  
  536.     s->line = 1;
  537.     s->lineinc = 0;
  538.     s->fd = fd;
  539.     s->filename = name;
  540.     s->next = cursource;
  541.     s->ifdepth = 0;
  542.     cursource = s;
  543.     /* slop at right for EOB */
  544.     if (str) {
  545.         len = strlen(str);
  546.         s->inb = domalloc(len+4);
  547.         s->inp = s->inb;
  548.         strncpy((char *)s->inp, str, len);
  549.     } else {
  550.         s->inb = domalloc(INS+4);
  551.         s->inp = s->inb;
  552.         len = 0;
  553.     }
  554.     s->inl = s->inp+len;
  555.     s->inl[0] = s->inl[1] = EOB;
  556.     return s;
  557. }
  558.  
  559. void
  560. unsetsource(void)
  561. {
  562.     Source *s = cursource;
  563.  
  564.     if (s->fd>=0) {
  565.         close(s->fd);
  566.         dofree(s->inb);
  567.     }
  568.     cursource = s->next;
  569.     dofree(s);
  570. }
  571.