13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 33e12c5d1SDavid du Colombier #include <stdio.h> 43e12c5d1SDavid du Colombier #include "cpp.h" 53e12c5d1SDavid du Colombier 63e12c5d1SDavid du Colombier /* 73e12c5d1SDavid du Colombier * lexical FSM encoding 83e12c5d1SDavid du Colombier * when in state state, and one of the characters 93e12c5d1SDavid du Colombier * in ch arrives, enter nextstate. 103e12c5d1SDavid du Colombier * States >= S_SELF are either final, or at least require special action. 113e12c5d1SDavid du Colombier * In 'fsm' there is a line for each state X charset X nextstate. 123e12c5d1SDavid du Colombier * List chars that overwrite previous entries later (e.g. C_ALPH 133e12c5d1SDavid du Colombier * can be overridden by '_' by a later entry; and C_XX is the 143e12c5d1SDavid du Colombier * the universal set, and should always be first. 153e12c5d1SDavid du Colombier * States above S_SELF are represented in the big table as negative values. 163e12c5d1SDavid du Colombier * S_SELF and S_SELFB encode the resulting token type in the upper bits. 173e12c5d1SDavid du Colombier * These actions differ in that S_SELF doesn't have a lookahead char, 183e12c5d1SDavid du Colombier * S_SELFB does. 193e12c5d1SDavid du Colombier * 203e12c5d1SDavid du Colombier * The encoding is blown out into a big table for time-efficiency. 213e12c5d1SDavid du Colombier * Entries have 223e12c5d1SDavid du Colombier * nextstate: 6 bits; ?\ marker: 1 bit; tokentype: 9 bits. 233e12c5d1SDavid du Colombier */ 243e12c5d1SDavid du Colombier 253e12c5d1SDavid du Colombier #define MAXSTATE 32 263e12c5d1SDavid du Colombier #define ACT(tok,act) ((tok<<7)+act) 273e12c5d1SDavid du Colombier #define QBSBIT 0100 283e12c5d1SDavid du Colombier #define GETACT(st) (st>>7)&0x1ff 293e12c5d1SDavid du Colombier 303e12c5d1SDavid du Colombier #define UTF2(c) ((c)>=0xA0 && (c)<0xE0) /* 2-char UTF seq */ 313e12c5d1SDavid du Colombier #define UTF3(c) ((c)>=0xE0 && (c)<0xF0) /* 3-char UTF seq */ 323e12c5d1SDavid du Colombier 333e12c5d1SDavid du Colombier /* character classes */ 343e12c5d1SDavid du Colombier #define C_WS 1 353e12c5d1SDavid du Colombier #define C_ALPH 2 363e12c5d1SDavid du Colombier #define C_NUM 3 373e12c5d1SDavid du Colombier #define C_EOF 4 383e12c5d1SDavid du Colombier #define C_XX 5 393e12c5d1SDavid du Colombier 403e12c5d1SDavid du Colombier enum state { 413e12c5d1SDavid du Colombier START=0, NUM1, NUM2, NUM3, ID1, ST1, ST2, ST3, COM1, COM2, COM3, COM4, 423e12c5d1SDavid du Colombier CC1, CC2, WS1, PLUS1, MINUS1, STAR1, SLASH1, PCT1, SHARP1, 433e12c5d1SDavid du Colombier CIRC1, GT1, GT2, LT1, LT2, OR1, AND1, ASG1, NOT1, DOTS1, 443e12c5d1SDavid du Colombier S_SELF=MAXSTATE, S_SELFB, S_EOF, S_NL, S_EOFSTR, 453e12c5d1SDavid du Colombier S_STNL, S_COMNL, S_EOFCOM, S_COMMENT, S_EOB, S_WS, S_NAME 463e12c5d1SDavid du Colombier }; 473e12c5d1SDavid du Colombier 483e12c5d1SDavid du Colombier int tottok; 493e12c5d1SDavid du Colombier int tokkind[256]; 503e12c5d1SDavid du Colombier struct fsm { 513e12c5d1SDavid du Colombier int state; /* if in this state */ 523e12c5d1SDavid du Colombier uchar ch[4]; /* and see one of these characters */ 533e12c5d1SDavid du Colombier int nextstate; /* enter this state if +ve */ 543e12c5d1SDavid du Colombier }; 553e12c5d1SDavid du Colombier 563e12c5d1SDavid du Colombier /*const*/ struct fsm fsm[] = { 573e12c5d1SDavid du Colombier /* start state */ 583e12c5d1SDavid du Colombier START, { C_XX }, ACT(UNCLASS,S_SELF), 597dd7cddfSDavid du Colombier START, { ' ', '\t', '\v', '\r' }, WS1, 603e12c5d1SDavid du Colombier START, { C_NUM }, NUM1, 613e12c5d1SDavid du Colombier START, { '.' }, NUM3, 623e12c5d1SDavid du Colombier START, { C_ALPH }, ID1, 633e12c5d1SDavid du Colombier START, { 'L' }, ST1, 643e12c5d1SDavid du Colombier START, { '"' }, ST2, 653e12c5d1SDavid du Colombier START, { '\'' }, CC1, 663e12c5d1SDavid du Colombier START, { '/' }, COM1, 67bd389b36SDavid du Colombier START, { EOFC }, S_EOF, 683e12c5d1SDavid du Colombier START, { '\n' }, S_NL, 693e12c5d1SDavid du Colombier START, { '-' }, MINUS1, 703e12c5d1SDavid du Colombier START, { '+' }, PLUS1, 713e12c5d1SDavid du Colombier START, { '<' }, LT1, 723e12c5d1SDavid du Colombier START, { '>' }, GT1, 733e12c5d1SDavid du Colombier START, { '=' }, ASG1, 743e12c5d1SDavid du Colombier START, { '!' }, NOT1, 753e12c5d1SDavid du Colombier START, { '&' }, AND1, 763e12c5d1SDavid du Colombier START, { '|' }, OR1, 773e12c5d1SDavid du Colombier START, { '#' }, SHARP1, 783e12c5d1SDavid du Colombier START, { '%' }, PCT1, 793e12c5d1SDavid du Colombier START, { '[' }, ACT(SBRA,S_SELF), 803e12c5d1SDavid du Colombier START, { ']' }, ACT(SKET,S_SELF), 813e12c5d1SDavid du Colombier START, { '(' }, ACT(LP,S_SELF), 823e12c5d1SDavid du Colombier START, { ')' }, ACT(RP,S_SELF), 833e12c5d1SDavid du Colombier START, { '*' }, STAR1, 843e12c5d1SDavid du Colombier START, { ',' }, ACT(COMMA,S_SELF), 853e12c5d1SDavid du Colombier START, { '?' }, ACT(QUEST,S_SELF), 863e12c5d1SDavid du Colombier START, { ':' }, ACT(COLON,S_SELF), 873e12c5d1SDavid du Colombier START, { ';' }, ACT(SEMIC,S_SELF), 883e12c5d1SDavid du Colombier START, { '{' }, ACT(CBRA,S_SELF), 893e12c5d1SDavid du Colombier START, { '}' }, ACT(CKET,S_SELF), 903e12c5d1SDavid du Colombier START, { '~' }, ACT(TILDE,S_SELF), 913e12c5d1SDavid du Colombier START, { '^' }, CIRC1, 923e12c5d1SDavid du Colombier 933e12c5d1SDavid du Colombier /* saw a digit */ 943e12c5d1SDavid du Colombier NUM1, { C_XX }, ACT(NUMBER,S_SELFB), 953e12c5d1SDavid du Colombier NUM1, { C_NUM, C_ALPH, '.' }, NUM1, 963e12c5d1SDavid du Colombier NUM1, { 'E', 'e' }, NUM2, 973e12c5d1SDavid du Colombier NUM1, { '_' }, ACT(NUMBER,S_SELFB), 983e12c5d1SDavid du Colombier 993e12c5d1SDavid du Colombier /* saw possible start of exponent, digits-e */ 1003e12c5d1SDavid du Colombier NUM2, { C_XX }, ACT(NUMBER,S_SELFB), 1013e12c5d1SDavid du Colombier NUM2, { '+', '-' }, NUM1, 1023e12c5d1SDavid du Colombier NUM2, { C_NUM, C_ALPH }, NUM1, 1033e12c5d1SDavid du Colombier NUM2, { '_' }, ACT(NUMBER,S_SELFB), 1043e12c5d1SDavid du Colombier 1053e12c5d1SDavid du Colombier /* saw a '.', which could be a number or an operator */ 1063e12c5d1SDavid du Colombier NUM3, { C_XX }, ACT(DOT,S_SELFB), 1073e12c5d1SDavid du Colombier NUM3, { '.' }, DOTS1, 1083e12c5d1SDavid du Colombier NUM3, { C_NUM }, NUM1, 1093e12c5d1SDavid du Colombier 1103e12c5d1SDavid du Colombier DOTS1, { C_XX }, ACT(UNCLASS, S_SELFB), 1113e12c5d1SDavid du Colombier DOTS1, { C_NUM }, NUM1, 1123e12c5d1SDavid du Colombier DOTS1, { '.' }, ACT(ELLIPS, S_SELF), 1133e12c5d1SDavid du Colombier 1143e12c5d1SDavid du Colombier /* saw a letter or _ */ 1153e12c5d1SDavid du Colombier ID1, { C_XX }, ACT(NAME,S_NAME), 1163e12c5d1SDavid du Colombier ID1, { C_ALPH, C_NUM }, ID1, 1173e12c5d1SDavid du Colombier 1183e12c5d1SDavid du Colombier /* saw L (start of wide string?) */ 1193e12c5d1SDavid du Colombier ST1, { C_XX }, ACT(NAME,S_NAME), 1203e12c5d1SDavid du Colombier ST1, { C_ALPH, C_NUM }, ID1, 1213e12c5d1SDavid du Colombier ST1, { '"' }, ST2, 1223e12c5d1SDavid du Colombier ST1, { '\'' }, CC1, 1233e12c5d1SDavid du Colombier 1243e12c5d1SDavid du Colombier /* saw " beginning string */ 1253e12c5d1SDavid du Colombier ST2, { C_XX }, ST2, 1263e12c5d1SDavid du Colombier ST2, { '"' }, ACT(STRING, S_SELF), 1273e12c5d1SDavid du Colombier ST2, { '\\' }, ST3, 1283e12c5d1SDavid du Colombier ST2, { '\n' }, S_STNL, 129bd389b36SDavid du Colombier ST2, { EOFC }, S_EOFSTR, 1303e12c5d1SDavid du Colombier 1313e12c5d1SDavid du Colombier /* saw \ in string */ 1323e12c5d1SDavid du Colombier ST3, { C_XX }, ST2, 1333e12c5d1SDavid du Colombier ST3, { '\n' }, S_STNL, 134bd389b36SDavid du Colombier ST3, { EOFC }, S_EOFSTR, 1353e12c5d1SDavid du Colombier 1363e12c5d1SDavid du Colombier /* saw ' beginning character const */ 1373e12c5d1SDavid du Colombier CC1, { C_XX }, CC1, 1383e12c5d1SDavid du Colombier CC1, { '\'' }, ACT(CCON, S_SELF), 1393e12c5d1SDavid du Colombier CC1, { '\\' }, CC2, 1403e12c5d1SDavid du Colombier CC1, { '\n' }, S_STNL, 141bd389b36SDavid du Colombier CC1, { EOFC }, S_EOFSTR, 1423e12c5d1SDavid du Colombier 1433e12c5d1SDavid du Colombier /* saw \ in ccon */ 1443e12c5d1SDavid du Colombier CC2, { C_XX }, CC1, 1453e12c5d1SDavid du Colombier CC2, { '\n' }, S_STNL, 146bd389b36SDavid du Colombier CC2, { EOFC }, S_EOFSTR, 1473e12c5d1SDavid du Colombier 1483e12c5d1SDavid du Colombier /* saw /, perhaps start of comment */ 1493e12c5d1SDavid du Colombier COM1, { C_XX }, ACT(SLASH, S_SELFB), 1503e12c5d1SDavid du Colombier COM1, { '=' }, ACT(ASSLASH, S_SELF), 1513e12c5d1SDavid du Colombier COM1, { '*' }, COM2, 1523e12c5d1SDavid du Colombier COM1, { '/' }, COM4, 1533e12c5d1SDavid du Colombier 1543e12c5d1SDavid du Colombier /* saw "/*", start of comment */ 1553e12c5d1SDavid du Colombier COM2, { C_XX }, COM2, 1563e12c5d1SDavid du Colombier COM2, { '\n' }, S_COMNL, 1573e12c5d1SDavid du Colombier COM2, { '*' }, COM3, 158bd389b36SDavid du Colombier COM2, { EOFC }, S_EOFCOM, 1593e12c5d1SDavid du Colombier 1603e12c5d1SDavid du Colombier /* saw the * possibly ending a comment */ 1613e12c5d1SDavid du Colombier COM3, { C_XX }, COM2, 1623e12c5d1SDavid du Colombier COM3, { '\n' }, S_COMNL, 1633e12c5d1SDavid du Colombier COM3, { '*' }, COM3, 1643e12c5d1SDavid du Colombier COM3, { '/' }, S_COMMENT, 1657dd7cddfSDavid du Colombier COM3, { EOFC }, S_EOFCOM, 1663e12c5d1SDavid du Colombier 1673e12c5d1SDavid du Colombier /* // comment */ 1683e12c5d1SDavid du Colombier COM4, { C_XX }, COM4, 1693e12c5d1SDavid du Colombier COM4, { '\n' }, S_NL, 170bd389b36SDavid du Colombier COM4, { EOFC }, S_EOFCOM, 1713e12c5d1SDavid du Colombier 1723e12c5d1SDavid du Colombier /* saw white space, eat it up */ 1733e12c5d1SDavid du Colombier WS1, { C_XX }, S_WS, 1747dd7cddfSDavid du Colombier WS1, { ' ', '\t', '\v', '\r'}, WS1, 1753e12c5d1SDavid du Colombier 1763e12c5d1SDavid du Colombier /* saw -, check --, -=, -> */ 1773e12c5d1SDavid du Colombier MINUS1, { C_XX }, ACT(MINUS, S_SELFB), 1783e12c5d1SDavid du Colombier MINUS1, { '-' }, ACT(MMINUS, S_SELF), 1793e12c5d1SDavid du Colombier MINUS1, { '=' }, ACT(ASMINUS,S_SELF), 1803e12c5d1SDavid du Colombier MINUS1, { '>' }, ACT(ARROW,S_SELF), 1813e12c5d1SDavid du Colombier 1823e12c5d1SDavid du Colombier /* saw +, check ++, += */ 1833e12c5d1SDavid du Colombier PLUS1, { C_XX }, ACT(PLUS, S_SELFB), 1843e12c5d1SDavid du Colombier PLUS1, { '+' }, ACT(PPLUS, S_SELF), 1853e12c5d1SDavid du Colombier PLUS1, { '=' }, ACT(ASPLUS, S_SELF), 1863e12c5d1SDavid du Colombier 1873e12c5d1SDavid du Colombier /* saw <, check <<, <<=, <= */ 1883e12c5d1SDavid du Colombier LT1, { C_XX }, ACT(LT, S_SELFB), 1893e12c5d1SDavid du Colombier LT1, { '<' }, LT2, 1903e12c5d1SDavid du Colombier LT1, { '=' }, ACT(LEQ, S_SELF), 1913e12c5d1SDavid du Colombier LT2, { C_XX }, ACT(LSH, S_SELFB), 1923e12c5d1SDavid du Colombier LT2, { '=' }, ACT(ASLSH, S_SELF), 1933e12c5d1SDavid du Colombier 1943e12c5d1SDavid du Colombier /* saw >, check >>, >>=, >= */ 1953e12c5d1SDavid du Colombier GT1, { C_XX }, ACT(GT, S_SELFB), 1963e12c5d1SDavid du Colombier GT1, { '>' }, GT2, 1973e12c5d1SDavid du Colombier GT1, { '=' }, ACT(GEQ, S_SELF), 1983e12c5d1SDavid du Colombier GT2, { C_XX }, ACT(RSH, S_SELFB), 1993e12c5d1SDavid du Colombier GT2, { '=' }, ACT(ASRSH, S_SELF), 2003e12c5d1SDavid du Colombier 2013e12c5d1SDavid du Colombier /* = */ 2023e12c5d1SDavid du Colombier ASG1, { C_XX }, ACT(ASGN, S_SELFB), 2033e12c5d1SDavid du Colombier ASG1, { '=' }, ACT(EQ, S_SELF), 2043e12c5d1SDavid du Colombier 2053e12c5d1SDavid du Colombier /* ! */ 2063e12c5d1SDavid du Colombier NOT1, { C_XX }, ACT(NOT, S_SELFB), 2073e12c5d1SDavid du Colombier NOT1, { '=' }, ACT(NEQ, S_SELF), 2083e12c5d1SDavid du Colombier 2093e12c5d1SDavid du Colombier /* & */ 2103e12c5d1SDavid du Colombier AND1, { C_XX }, ACT(AND, S_SELFB), 2113e12c5d1SDavid du Colombier AND1, { '&' }, ACT(LAND, S_SELF), 2123e12c5d1SDavid du Colombier AND1, { '=' }, ACT(ASAND, S_SELF), 2133e12c5d1SDavid du Colombier 2143e12c5d1SDavid du Colombier /* | */ 2153e12c5d1SDavid du Colombier OR1, { C_XX }, ACT(OR, S_SELFB), 2163e12c5d1SDavid du Colombier OR1, { '|' }, ACT(LOR, S_SELF), 2173e12c5d1SDavid du Colombier OR1, { '=' }, ACT(ASOR, S_SELF), 2183e12c5d1SDavid du Colombier 2193e12c5d1SDavid du Colombier /* # */ 2203e12c5d1SDavid du Colombier SHARP1, { C_XX }, ACT(SHARP, S_SELFB), 2213e12c5d1SDavid du Colombier SHARP1, { '#' }, ACT(DSHARP, S_SELF), 2223e12c5d1SDavid du Colombier 2233e12c5d1SDavid du Colombier /* % */ 2243e12c5d1SDavid du Colombier PCT1, { C_XX }, ACT(PCT, S_SELFB), 2253e12c5d1SDavid du Colombier PCT1, { '=' }, ACT(ASPCT, S_SELF), 2263e12c5d1SDavid du Colombier 2273e12c5d1SDavid du Colombier /* * */ 2283e12c5d1SDavid du Colombier STAR1, { C_XX }, ACT(STAR, S_SELFB), 2293e12c5d1SDavid du Colombier STAR1, { '=' }, ACT(ASSTAR, S_SELF), 2303e12c5d1SDavid du Colombier 2313e12c5d1SDavid du Colombier /* ^ */ 2323e12c5d1SDavid du Colombier CIRC1, { C_XX }, ACT(CIRC, S_SELFB), 2333e12c5d1SDavid du Colombier CIRC1, { '=' }, ACT(ASCIRC, S_SELF), 2343e12c5d1SDavid du Colombier 2353e12c5d1SDavid du Colombier -1 2363e12c5d1SDavid du Colombier }; 2373e12c5d1SDavid du Colombier 238bd389b36SDavid du Colombier /* first index is char, second is state */ 2393e12c5d1SDavid du Colombier /* increase #states to power of 2 to encourage use of shift */ 240bd389b36SDavid du Colombier short bigfsm[256][MAXSTATE]; 2413e12c5d1SDavid du Colombier 2423e12c5d1SDavid du Colombier void 2433e12c5d1SDavid du Colombier expandlex(void) 2443e12c5d1SDavid du Colombier { 2453e12c5d1SDavid du Colombier /*const*/ struct fsm *fp; 2463e12c5d1SDavid du Colombier int i, j, nstate; 2473e12c5d1SDavid du Colombier 2483e12c5d1SDavid du Colombier for (fp = fsm; fp->state>=0; fp++) { 2493e12c5d1SDavid du Colombier for (i=0; fp->ch[i]; i++) { 2503e12c5d1SDavid du Colombier nstate = fp->nextstate; 2513e12c5d1SDavid du Colombier if (nstate >= S_SELF) 2523e12c5d1SDavid du Colombier nstate = ~nstate; 2533e12c5d1SDavid du Colombier switch (fp->ch[i]) { 2543e12c5d1SDavid du Colombier 2553e12c5d1SDavid du Colombier case C_XX: /* random characters */ 256bd389b36SDavid du Colombier for (j=0; j<256; j++) 2573e12c5d1SDavid du Colombier bigfsm[j][fp->state] = nstate; 2583e12c5d1SDavid du Colombier continue; 2593e12c5d1SDavid du Colombier case C_ALPH: 260bd389b36SDavid du Colombier for (j=0; j<=256; j++) 2613e12c5d1SDavid du Colombier if ('a'<=j&&j<='z' || 'A'<=j&&j<='Z' 2623e12c5d1SDavid du Colombier || UTF2(j) || UTF3(j) || j=='_') 263bd389b36SDavid du Colombier bigfsm[j][fp->state] = nstate; 2643e12c5d1SDavid du Colombier continue; 2653e12c5d1SDavid du Colombier case C_NUM: 2663e12c5d1SDavid du Colombier for (j='0'; j<='9'; j++) 267bd389b36SDavid du Colombier bigfsm[j][fp->state] = nstate; 2683e12c5d1SDavid du Colombier continue; 2693e12c5d1SDavid du Colombier default: 270bd389b36SDavid du Colombier bigfsm[fp->ch[i]][fp->state] = nstate; 2713e12c5d1SDavid du Colombier } 2723e12c5d1SDavid du Colombier } 2733e12c5d1SDavid du Colombier } 2743e12c5d1SDavid du Colombier /* install special cases for ? (trigraphs), \ (splicing), runes, and EOB */ 2753e12c5d1SDavid du Colombier for (i=0; i<MAXSTATE; i++) { 2763e12c5d1SDavid du Colombier for (j=0; j<0xFF; j++) 2773e12c5d1SDavid du Colombier if (j=='?' || j=='\\' || UTF2(j) || UTF3(j)) { 278bd389b36SDavid du Colombier if (bigfsm[j][i]>0) 279bd389b36SDavid du Colombier bigfsm[j][i] = ~bigfsm[j][i]; 280bd389b36SDavid du Colombier bigfsm[j][i] &= ~QBSBIT; 2813e12c5d1SDavid du Colombier } 282bd389b36SDavid du Colombier bigfsm[EOB][i] = ~S_EOB; 283bd389b36SDavid du Colombier if (bigfsm[EOFC][i]>=0) 284bd389b36SDavid du Colombier bigfsm[EOFC][i] = ~S_EOF; 2853e12c5d1SDavid du Colombier } 2863e12c5d1SDavid du Colombier } 2873e12c5d1SDavid du Colombier 2883e12c5d1SDavid du Colombier void 2893e12c5d1SDavid du Colombier fixlex(void) 2903e12c5d1SDavid du Colombier { 2913e12c5d1SDavid du Colombier /* do C++ comments? */ 2923e12c5d1SDavid du Colombier if (Cplusplus==0) 293bd389b36SDavid du Colombier bigfsm['/'][COM1] = bigfsm['x'][COM1]; 2943e12c5d1SDavid du Colombier } 2953e12c5d1SDavid du Colombier 2963e12c5d1SDavid du Colombier /* 2973e12c5d1SDavid du Colombier * fill in a row of tokens from input, terminated by NL or END 2983e12c5d1SDavid du Colombier * First token is put at trp->lp. 2993e12c5d1SDavid du Colombier * Reset is non-zero when the input buffer can be "rewound." 3003e12c5d1SDavid du Colombier * The value is a flag indicating that possible macros have 3013e12c5d1SDavid du Colombier * been seen in the row. 3023e12c5d1SDavid du Colombier */ 3033e12c5d1SDavid du Colombier int 3043e12c5d1SDavid du Colombier gettokens(Tokenrow *trp, int reset) 3053e12c5d1SDavid du Colombier { 3063e12c5d1SDavid du Colombier register int c, state, oldstate; 3073e12c5d1SDavid du Colombier register uchar *ip; 3083e12c5d1SDavid du Colombier register Token *tp, *maxp; 3093e12c5d1SDavid du Colombier int runelen; 3103e12c5d1SDavid du Colombier Source *s = cursource; 3113e12c5d1SDavid du Colombier int nmac = 0; 3123e12c5d1SDavid du Colombier extern char outbuf[]; 3133e12c5d1SDavid du Colombier 3143e12c5d1SDavid du Colombier tp = trp->lp; 3153e12c5d1SDavid du Colombier ip = s->inp; 3163e12c5d1SDavid du Colombier if (reset) { 3173e12c5d1SDavid du Colombier s->lineinc = 0; 3183e12c5d1SDavid du Colombier if (ip>=s->inl) { /* nothing in buffer */ 3193e12c5d1SDavid du Colombier s->inl = s->inb; 3203e12c5d1SDavid du Colombier fillbuf(s); 3213e12c5d1SDavid du Colombier ip = s->inp = s->inb; 322*a8453668SDavid du Colombier } else if (ip >= s->inb+(3*s->ins/4)) { 3233e12c5d1SDavid du Colombier memmove(s->inb, ip, 4+s->inl-ip); 3243e12c5d1SDavid du Colombier s->inl = s->inb+(s->inl-ip); 3253e12c5d1SDavid du Colombier ip = s->inp = s->inb; 3263e12c5d1SDavid du Colombier } 3273e12c5d1SDavid du Colombier } 3283e12c5d1SDavid du Colombier maxp = &trp->bp[trp->max]; 3293e12c5d1SDavid du Colombier runelen = 1; 3303e12c5d1SDavid du Colombier for (;;) { 3313e12c5d1SDavid du Colombier continue2: 3323e12c5d1SDavid du Colombier if (tp>=maxp) { 3333e12c5d1SDavid du Colombier trp->lp = tp; 3343e12c5d1SDavid du Colombier tp = growtokenrow(trp); 3353e12c5d1SDavid du Colombier maxp = &trp->bp[trp->max]; 3363e12c5d1SDavid du Colombier } 3373e12c5d1SDavid du Colombier tp->type = UNCLASS; 3383e12c5d1SDavid du Colombier tp->hideset = 0; 3393e12c5d1SDavid du Colombier tp->t = ip; 3403e12c5d1SDavid du Colombier tp->wslen = 0; 3413e12c5d1SDavid du Colombier tp->flag = 0; 3423e12c5d1SDavid du Colombier state = START; 3433e12c5d1SDavid du Colombier for (;;) { 3443e12c5d1SDavid du Colombier oldstate = state; 3453e12c5d1SDavid du Colombier c = *ip; 346bd389b36SDavid du Colombier if ((state = bigfsm[c][state]) >= 0) { 3473e12c5d1SDavid du Colombier ip += runelen; 3483e12c5d1SDavid du Colombier runelen = 1; 3493e12c5d1SDavid du Colombier continue; 3503e12c5d1SDavid du Colombier } 3513e12c5d1SDavid du Colombier state = ~state; 3523e12c5d1SDavid du Colombier reswitch: 3533e12c5d1SDavid du Colombier switch (state&0177) { 3543e12c5d1SDavid du Colombier case S_SELF: 3553e12c5d1SDavid du Colombier ip += runelen; 3563e12c5d1SDavid du Colombier runelen = 1; 3573e12c5d1SDavid du Colombier case S_SELFB: 3583e12c5d1SDavid du Colombier tp->type = GETACT(state); 3593e12c5d1SDavid du Colombier tp->len = ip - tp->t; 3603e12c5d1SDavid du Colombier tp++; 3613e12c5d1SDavid du Colombier goto continue2; 3623e12c5d1SDavid du Colombier 3633e12c5d1SDavid du Colombier case S_NAME: /* like S_SELFB but with nmac check */ 3643e12c5d1SDavid du Colombier tp->type = NAME; 3653e12c5d1SDavid du Colombier tp->len = ip - tp->t; 3663e12c5d1SDavid du Colombier nmac |= quicklook(tp->t[0], tp->len>1?tp->t[1]:0); 3673e12c5d1SDavid du Colombier tp++; 3683e12c5d1SDavid du Colombier goto continue2; 3693e12c5d1SDavid du Colombier 3703e12c5d1SDavid du Colombier case S_WS: 3713e12c5d1SDavid du Colombier tp->wslen = ip - tp->t; 3723e12c5d1SDavid du Colombier tp->t = ip; 3733e12c5d1SDavid du Colombier state = START; 3743e12c5d1SDavid du Colombier continue; 3753e12c5d1SDavid du Colombier 3763e12c5d1SDavid du Colombier default: 3773e12c5d1SDavid du Colombier if ((state&QBSBIT)==0) { 3783e12c5d1SDavid du Colombier ip += runelen; 3793e12c5d1SDavid du Colombier runelen = 1; 3803e12c5d1SDavid du Colombier continue; 3813e12c5d1SDavid du Colombier } 3823e12c5d1SDavid du Colombier state &= ~QBSBIT; 3833e12c5d1SDavid du Colombier s->inp = ip; 3843e12c5d1SDavid du Colombier if (c=='?') { /* check trigraph */ 3853e12c5d1SDavid du Colombier if (trigraph(s)) { 3863e12c5d1SDavid du Colombier state = oldstate; 3873e12c5d1SDavid du Colombier continue; 3883e12c5d1SDavid du Colombier } 3893e12c5d1SDavid du Colombier goto reswitch; 3903e12c5d1SDavid du Colombier } 3913e12c5d1SDavid du Colombier if (c=='\\') { /* line-folding */ 3923e12c5d1SDavid du Colombier if (foldline(s)) { 3933e12c5d1SDavid du Colombier s->lineinc++; 3943e12c5d1SDavid du Colombier state = oldstate; 3953e12c5d1SDavid du Colombier continue; 3963e12c5d1SDavid du Colombier } 3973e12c5d1SDavid du Colombier goto reswitch; 3983e12c5d1SDavid du Colombier } 3993e12c5d1SDavid du Colombier if (UTF2(c)) { 4003e12c5d1SDavid du Colombier runelen = 2; 4013e12c5d1SDavid du Colombier goto reswitch; 4023e12c5d1SDavid du Colombier } 4033e12c5d1SDavid du Colombier if (UTF3(c)) { 4043e12c5d1SDavid du Colombier runelen = 3; 4053e12c5d1SDavid du Colombier goto reswitch; 4063e12c5d1SDavid du Colombier } 4073e12c5d1SDavid du Colombier error(WARNING, "Lexical botch in cpp"); 4083e12c5d1SDavid du Colombier ip += runelen; 4093e12c5d1SDavid du Colombier runelen = 1; 4103e12c5d1SDavid du Colombier continue; 4113e12c5d1SDavid du Colombier 4123e12c5d1SDavid du Colombier case S_EOB: 4133e12c5d1SDavid du Colombier s->inp = ip; 4143e12c5d1SDavid du Colombier fillbuf(cursource); 4153e12c5d1SDavid du Colombier state = oldstate; 4163e12c5d1SDavid du Colombier continue; 4173e12c5d1SDavid du Colombier 4183e12c5d1SDavid du Colombier case S_EOF: 4193e12c5d1SDavid du Colombier tp->type = END; 4203e12c5d1SDavid du Colombier tp->len = 0; 4213e12c5d1SDavid du Colombier s->inp = ip; 4223e12c5d1SDavid du Colombier if (tp!=trp->bp && (tp-1)->type!=NL && cursource->fd!=-1) 4233e12c5d1SDavid du Colombier error(WARNING,"No newline at end of file"); 4243e12c5d1SDavid du Colombier trp->lp = tp+1; 4253e12c5d1SDavid du Colombier return nmac; 4263e12c5d1SDavid du Colombier 4273e12c5d1SDavid du Colombier case S_STNL: 4283e12c5d1SDavid du Colombier error(ERROR, "Unterminated string or char const"); 4293e12c5d1SDavid du Colombier case S_NL: 4303e12c5d1SDavid du Colombier tp->t = ip; 4313e12c5d1SDavid du Colombier tp->type = NL; 4323e12c5d1SDavid du Colombier tp->len = 1; 4333e12c5d1SDavid du Colombier tp->wslen = 0; 4343e12c5d1SDavid du Colombier s->lineinc++; 4353e12c5d1SDavid du Colombier s->inp = ip+1; 4363e12c5d1SDavid du Colombier trp->lp = tp+1; 4373e12c5d1SDavid du Colombier return nmac; 4383e12c5d1SDavid du Colombier 4393e12c5d1SDavid du Colombier case S_EOFSTR: 4403e12c5d1SDavid du Colombier error(FATAL, "EOF in string or char constant"); 4413e12c5d1SDavid du Colombier break; 4423e12c5d1SDavid du Colombier 4433e12c5d1SDavid du Colombier case S_COMNL: 4443e12c5d1SDavid du Colombier s->lineinc++; 4453e12c5d1SDavid du Colombier state = COM2; 4463e12c5d1SDavid du Colombier ip += runelen; 4473e12c5d1SDavid du Colombier runelen = 1; 448*a8453668SDavid du Colombier if (ip >= s->inb+(7*s->ins/8)) { /* very long comment */ 4497dd7cddfSDavid du Colombier memmove(tp->t, ip, 4+s->inl-ip); 4507dd7cddfSDavid du Colombier s->inl -= ip-tp->t; 4517dd7cddfSDavid du Colombier ip = tp->t+1; 4527dd7cddfSDavid du Colombier } 4533e12c5d1SDavid du Colombier continue; 4543e12c5d1SDavid du Colombier 4553e12c5d1SDavid du Colombier case S_EOFCOM: 4563e12c5d1SDavid du Colombier error(WARNING, "EOF inside comment"); 4573e12c5d1SDavid du Colombier --ip; 4583e12c5d1SDavid du Colombier case S_COMMENT: 4593e12c5d1SDavid du Colombier ++ip; 4603e12c5d1SDavid du Colombier tp->t = ip; 4613e12c5d1SDavid du Colombier tp->t[-1] = ' '; 4623e12c5d1SDavid du Colombier tp->wslen = 1; 4633e12c5d1SDavid du Colombier state = START; 4643e12c5d1SDavid du Colombier continue; 4653e12c5d1SDavid du Colombier } 4663e12c5d1SDavid du Colombier break; 4673e12c5d1SDavid du Colombier } 4683e12c5d1SDavid du Colombier ip += runelen; 4693e12c5d1SDavid du Colombier runelen = 1; 4703e12c5d1SDavid du Colombier tp->len = ip - tp->t; 4713e12c5d1SDavid du Colombier tp++; 4723e12c5d1SDavid du Colombier } 473bd389b36SDavid du Colombier return 0; 4743e12c5d1SDavid du Colombier } 4753e12c5d1SDavid du Colombier 4763e12c5d1SDavid du Colombier /* have seen ?; handle the trigraph it starts (if any) else 0 */ 4773e12c5d1SDavid du Colombier int 4783e12c5d1SDavid du Colombier trigraph(Source *s) 4793e12c5d1SDavid du Colombier { 4803e12c5d1SDavid du Colombier int c; 4813e12c5d1SDavid du Colombier 4823e12c5d1SDavid du Colombier while (s->inp+2 >= s->inl && fillbuf(s)!=EOF) 4833e12c5d1SDavid du Colombier ; 4843e12c5d1SDavid du Colombier if (s->inp[1]!='?') 4853e12c5d1SDavid du Colombier return 0; 4863e12c5d1SDavid du Colombier c = 0; 4873e12c5d1SDavid du Colombier switch(s->inp[2]) { 4883e12c5d1SDavid du Colombier case '=': 4893e12c5d1SDavid du Colombier c = '#'; break; 4903e12c5d1SDavid du Colombier case '(': 4913e12c5d1SDavid du Colombier c = '['; break; 4923e12c5d1SDavid du Colombier case '/': 4933e12c5d1SDavid du Colombier c = '\\'; break; 4943e12c5d1SDavid du Colombier case ')': 4953e12c5d1SDavid du Colombier c = ']'; break; 4963e12c5d1SDavid du Colombier case '\'': 4973e12c5d1SDavid du Colombier c = '^'; break; 4983e12c5d1SDavid du Colombier case '<': 4993e12c5d1SDavid du Colombier c = '{'; break; 5003e12c5d1SDavid du Colombier case '!': 5013e12c5d1SDavid du Colombier c = '|'; break; 5023e12c5d1SDavid du Colombier case '>': 5033e12c5d1SDavid du Colombier c = '}'; break; 5043e12c5d1SDavid du Colombier case '-': 5053e12c5d1SDavid du Colombier c = '~'; break; 5063e12c5d1SDavid du Colombier } 5073e12c5d1SDavid du Colombier if (c) { 5083e12c5d1SDavid du Colombier *s->inp = c; 5093e12c5d1SDavid du Colombier memmove(s->inp+1, s->inp+3, s->inl-s->inp+2); 5103e12c5d1SDavid du Colombier s->inl -= 2; 5113e12c5d1SDavid du Colombier } 5123e12c5d1SDavid du Colombier return c; 5133e12c5d1SDavid du Colombier } 5143e12c5d1SDavid du Colombier 5153e12c5d1SDavid du Colombier int 5163e12c5d1SDavid du Colombier foldline(Source *s) 5173e12c5d1SDavid du Colombier { 51859cc4ca5SDavid du Colombier int ncr = 0; 51959cc4ca5SDavid du Colombier 52059cc4ca5SDavid du Colombier recheck: 5213e12c5d1SDavid du Colombier while (s->inp+1 >= s->inl && fillbuf(s)!=EOF) 5223e12c5d1SDavid du Colombier ; 52359cc4ca5SDavid du Colombier if (s->inp[ncr+1] == '\r') { /* nonstandardly, ignore CR before line-folding */ 52459cc4ca5SDavid du Colombier ncr++; 52559cc4ca5SDavid du Colombier goto recheck; 52659cc4ca5SDavid du Colombier } 52759cc4ca5SDavid du Colombier if (s->inp[ncr+1] == '\n') { 52859cc4ca5SDavid du Colombier memmove(s->inp, s->inp+2+ncr, s->inl-s->inp+3-ncr); 52959cc4ca5SDavid du Colombier s->inl -= 2+ncr; 5303e12c5d1SDavid du Colombier return 1; 5313e12c5d1SDavid du Colombier } 5323e12c5d1SDavid du Colombier return 0; 5333e12c5d1SDavid du Colombier } 5343e12c5d1SDavid du Colombier 5353e12c5d1SDavid du Colombier int 5363e12c5d1SDavid du Colombier fillbuf(Source *s) 5373e12c5d1SDavid du Colombier { 5383e12c5d1SDavid du Colombier int n; 5393e12c5d1SDavid du Colombier 540*a8453668SDavid du Colombier while((char *)s->inl+s->ins/8 > (char *)s->inb+s->ins) { 541*a8453668SDavid du Colombier uint l = s->inl - s->inb; 542*a8453668SDavid du Colombier uint p = s->inp - s->inb; 543*a8453668SDavid du Colombier if(l < 0) 544*a8453668SDavid du Colombier error(FATAL, "negative end of input!?"); 545*a8453668SDavid du Colombier if(p < 0) 546*a8453668SDavid du Colombier error(FATAL, "negative input pointer!?"); 547*a8453668SDavid du Colombier /* double the buffer size and try again */ 548*a8453668SDavid du Colombier s->ins *= 2; 549*a8453668SDavid du Colombier s->inb = dorealloc(s->inb, s->ins); 550*a8453668SDavid du Colombier s->inl = s->inb + l; 551*a8453668SDavid du Colombier s->inp = s->inb + p; 552*a8453668SDavid du Colombier } 553*a8453668SDavid du Colombier if (s->fd<0 || (n=read(s->fd, (char *)s->inl, s->ins/8)) <= 0) 5543e12c5d1SDavid du Colombier n = 0; 5557dd7cddfSDavid du Colombier if ((*s->inp&0xff) == EOB) /* sentinel character appears in input */ 5567dd7cddfSDavid du Colombier *s->inp = EOFC; 5573e12c5d1SDavid du Colombier s->inl += n; 5583e12c5d1SDavid du Colombier s->inl[0] = s->inl[1]= s->inl[2]= s->inl[3] = EOB; 5593e12c5d1SDavid du Colombier if (n==0) { 560bd389b36SDavid du Colombier s->inl[0] = s->inl[1]= s->inl[2]= s->inl[3] = EOFC; 5613e12c5d1SDavid du Colombier return EOF; 5623e12c5d1SDavid du Colombier } 5633e12c5d1SDavid du Colombier return 0; 5643e12c5d1SDavid du Colombier } 5653e12c5d1SDavid du Colombier 5663e12c5d1SDavid du Colombier /* 5673e12c5d1SDavid du Colombier * Push down to new source of characters. 5683e12c5d1SDavid du Colombier * If fd>0 and str==NULL, then from a file `name'; 5693e12c5d1SDavid du Colombier * if fd==-1 and str, then from the string. 5703e12c5d1SDavid du Colombier */ 5713e12c5d1SDavid du Colombier Source * 5723e12c5d1SDavid du Colombier setsource(char *name, int fd, char *str) 5733e12c5d1SDavid du Colombier { 5743e12c5d1SDavid du Colombier Source *s = new(Source); 5753e12c5d1SDavid du Colombier int len; 5763e12c5d1SDavid du Colombier 5773e12c5d1SDavid du Colombier s->line = 1; 5783e12c5d1SDavid du Colombier s->lineinc = 0; 5793e12c5d1SDavid du Colombier s->fd = fd; 5803e12c5d1SDavid du Colombier s->filename = name; 581219b2ee8SDavid du Colombier s->next = cursource; 582219b2ee8SDavid du Colombier s->ifdepth = 0; 583219b2ee8SDavid du Colombier cursource = s; 5843e12c5d1SDavid du Colombier /* slop at right for EOB */ 5853e12c5d1SDavid du Colombier if (str) { 5863e12c5d1SDavid du Colombier len = strlen(str); 5873e12c5d1SDavid du Colombier s->inb = domalloc(len+4); 5883e12c5d1SDavid du Colombier s->inp = s->inb; 5893e12c5d1SDavid du Colombier strncpy((char *)s->inp, str, len); 5903e12c5d1SDavid du Colombier } else { 5919a747e4fSDavid du Colombier Dir *d; 5927dd7cddfSDavid du Colombier int junk; 5939a747e4fSDavid du Colombier ulong length = 0; 5949a747e4fSDavid du Colombier d = dirfstat(fd); 5959a747e4fSDavid du Colombier if (d != nil) { 5969a747e4fSDavid du Colombier length = d->length; 5979a747e4fSDavid du Colombier free(d); 5989a747e4fSDavid du Colombier } 5999a747e4fSDavid du Colombier junk = length; 6007dd7cddfSDavid du Colombier if (junk<INS) 6017dd7cddfSDavid du Colombier junk = INS; 6027dd7cddfSDavid du Colombier s->inb = domalloc((junk)+4); 6033e12c5d1SDavid du Colombier s->inp = s->inb; 6043e12c5d1SDavid du Colombier len = 0; 6053e12c5d1SDavid du Colombier } 606*a8453668SDavid du Colombier 607*a8453668SDavid du Colombier s->ins = INS; 6083e12c5d1SDavid du Colombier s->inl = s->inp+len; 6093e12c5d1SDavid du Colombier s->inl[0] = s->inl[1] = EOB; 6103e12c5d1SDavid du Colombier return s; 6113e12c5d1SDavid du Colombier } 6123e12c5d1SDavid du Colombier 6133e12c5d1SDavid du Colombier void 6143e12c5d1SDavid du Colombier unsetsource(void) 6153e12c5d1SDavid du Colombier { 6163e12c5d1SDavid du Colombier Source *s = cursource; 6173e12c5d1SDavid du Colombier 6183e12c5d1SDavid du Colombier if (s->fd>=0) { 6193e12c5d1SDavid du Colombier close(s->fd); 6203e12c5d1SDavid du Colombier dofree(s->inb); 6213e12c5d1SDavid du Colombier } 6223e12c5d1SDavid du Colombier cursource = s->next; 6233e12c5d1SDavid du Colombier dofree(s); 6243e12c5d1SDavid du Colombier } 625