diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/cpp/lex.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/cpp/lex.c')
-rwxr-xr-x | sys/src/cmd/cpp/lex.c | 623 |
1 files changed, 623 insertions, 0 deletions
diff --git a/sys/src/cmd/cpp/lex.c b/sys/src/cmd/cpp/lex.c new file mode 100755 index 000000000..30367c3f7 --- /dev/null +++ b/sys/src/cmd/cpp/lex.c @@ -0,0 +1,623 @@ +#include <u.h> +#include <libc.h> +#include <stdio.h> +#include "cpp.h" + +/* + * lexical FSM encoding + * when in state state, and one of the characters + * in ch arrives, enter nextstate. + * States >= S_SELF are either final, or at least require special action. + * In 'fsm' there is a line for each state X charset X nextstate. + * List chars that overwrite previous entries later (e.g. C_ALPH + * can be overridden by '_' by a later entry; and C_XX is the + * the universal set, and should always be first. + * States above S_SELF are represented in the big table as negative values. + * S_SELF and S_SELFB encode the resulting token type in the upper bits. + * These actions differ in that S_SELF doesn't have a lookahead char, + * S_SELFB does. + * + * The encoding is blown out into a big table for time-efficiency. + * Entries have + * nextstate: 6 bits; ?\ marker: 1 bit; tokentype: 9 bits. + */ + +#define MAXSTATE 32 +#define ACT(tok,act) ((tok<<7)+act) +#define QBSBIT 0100 +#define GETACT(st) (st>>7)&0x1ff + +#define UTF2(c) ((c)>=0xA0 && (c)<0xE0) /* 2-char UTF seq */ +#define UTF3(c) ((c)>=0xE0 && (c)<0xF0) /* 3-char UTF seq */ + +/* character classes */ +#define C_WS 1 +#define C_ALPH 2 +#define C_NUM 3 +#define C_EOF 4 +#define C_XX 5 + +enum state { + START=0, NUM1, NUM2, NUM3, ID1, ST1, ST2, ST3, COM1, COM2, COM3, COM4, + CC1, CC2, WS1, PLUS1, MINUS1, STAR1, SLASH1, PCT1, SHARP1, + CIRC1, GT1, GT2, LT1, LT2, OR1, AND1, ASG1, NOT1, DOTS1, + S_SELF=MAXSTATE, S_SELFB, S_EOF, S_NL, S_EOFSTR, + S_STNL, S_COMNL, S_EOFCOM, S_COMMENT, S_EOB, S_WS, S_NAME +}; + +int tottok; +int tokkind[256]; +struct fsm { + int state; /* if in this state */ + uchar ch[4]; /* and see one of these characters */ + int nextstate; /* enter this state if +ve */ +}; + +/*const*/ struct fsm fsm[] = { + /* start state */ + START, { C_XX }, ACT(UNCLASS,S_SELF), + START, { ' ', '\t', '\v', '\r' }, WS1, + START, { C_NUM }, NUM1, + START, { '.' }, NUM3, + START, { C_ALPH }, ID1, + START, { 'L' }, ST1, + START, { '"' }, ST2, + START, { '\'' }, CC1, + START, { '/' }, COM1, + START, { EOFC }, S_EOF, + START, { '\n' }, S_NL, + START, { '-' }, MINUS1, + START, { '+' }, PLUS1, + START, { '<' }, LT1, + START, { '>' }, GT1, + START, { '=' }, ASG1, + START, { '!' }, NOT1, + START, { '&' }, AND1, + START, { '|' }, OR1, + START, { '#' }, SHARP1, + START, { '%' }, PCT1, + START, { '[' }, ACT(SBRA,S_SELF), + START, { ']' }, ACT(SKET,S_SELF), + START, { '(' }, ACT(LP,S_SELF), + START, { ')' }, ACT(RP,S_SELF), + START, { '*' }, STAR1, + START, { ',' }, ACT(COMMA,S_SELF), + START, { '?' }, ACT(QUEST,S_SELF), + START, { ':' }, ACT(COLON,S_SELF), + START, { ';' }, ACT(SEMIC,S_SELF), + START, { '{' }, ACT(CBRA,S_SELF), + START, { '}' }, ACT(CKET,S_SELF), + START, { '~' }, ACT(TILDE,S_SELF), + START, { '^' }, CIRC1, + + /* saw a digit */ + NUM1, { C_XX }, ACT(NUMBER,S_SELFB), + NUM1, { C_NUM, C_ALPH, '.' }, NUM1, + NUM1, { 'E', 'e' }, NUM2, + NUM1, { '_' }, ACT(NUMBER,S_SELFB), + + /* saw possible start of exponent, digits-e */ + NUM2, { C_XX }, ACT(NUMBER,S_SELFB), + NUM2, { '+', '-' }, NUM1, + NUM2, { C_NUM, C_ALPH }, NUM1, + NUM2, { '_' }, ACT(NUMBER,S_SELFB), + + /* saw a '.', which could be a number or an operator */ + NUM3, { C_XX }, ACT(DOT,S_SELFB), + NUM3, { '.' }, DOTS1, + NUM3, { C_NUM }, NUM1, + + DOTS1, { C_XX }, ACT(UNCLASS, S_SELFB), + DOTS1, { C_NUM }, NUM1, + DOTS1, { '.' }, ACT(ELLIPS, S_SELF), + + /* saw a letter or _ */ + ID1, { C_XX }, ACT(NAME,S_NAME), + ID1, { C_ALPH, C_NUM }, ID1, + + /* saw L (start of wide string?) */ + ST1, { C_XX }, ACT(NAME,S_NAME), + ST1, { C_ALPH, C_NUM }, ID1, + ST1, { '"' }, ST2, + ST1, { '\'' }, CC1, + + /* saw " beginning string */ + ST2, { C_XX }, ST2, + ST2, { '"' }, ACT(STRING, S_SELF), + ST2, { '\\' }, ST3, + ST2, { '\n' }, S_STNL, + ST2, { EOFC }, S_EOFSTR, + + /* saw \ in string */ + ST3, { C_XX }, ST2, + ST3, { '\n' }, S_STNL, + ST3, { EOFC }, S_EOFSTR, + + /* saw ' beginning character const */ + CC1, { C_XX }, CC1, + CC1, { '\'' }, ACT(CCON, S_SELF), + CC1, { '\\' }, CC2, + CC1, { '\n' }, S_STNL, + CC1, { EOFC }, S_EOFSTR, + + /* saw \ in ccon */ + CC2, { C_XX }, CC1, + CC2, { '\n' }, S_STNL, + CC2, { EOFC }, S_EOFSTR, + + /* saw /, perhaps start of comment */ + COM1, { C_XX }, ACT(SLASH, S_SELFB), + COM1, { '=' }, ACT(ASSLASH, S_SELF), + COM1, { '*' }, COM2, + COM1, { '/' }, COM4, + + /* saw "/*", start of comment */ + COM2, { C_XX }, COM2, + COM2, { '\n' }, S_COMNL, + COM2, { '*' }, COM3, + COM2, { EOFC }, S_EOFCOM, + + /* saw the * possibly ending a comment */ + COM3, { C_XX }, COM2, + COM3, { '\n' }, S_COMNL, + COM3, { '*' }, COM3, + COM3, { '/' }, S_COMMENT, + COM3, { EOFC }, S_EOFCOM, + + /* // comment */ + COM4, { C_XX }, COM4, + COM4, { '\n' }, S_NL, + COM4, { EOFC }, S_EOFCOM, + + /* saw white space, eat it up */ + WS1, { C_XX }, S_WS, + WS1, { ' ', '\t', '\v', '\r'}, WS1, + + /* saw -, check --, -=, -> */ + MINUS1, { C_XX }, ACT(MINUS, S_SELFB), + MINUS1, { '-' }, ACT(MMINUS, S_SELF), + MINUS1, { '=' }, ACT(ASMINUS,S_SELF), + MINUS1, { '>' }, ACT(ARROW,S_SELF), + + /* saw +, check ++, += */ + PLUS1, { C_XX }, ACT(PLUS, S_SELFB), + PLUS1, { '+' }, ACT(PPLUS, S_SELF), + PLUS1, { '=' }, ACT(ASPLUS, S_SELF), + + /* saw <, check <<, <<=, <= */ + LT1, { C_XX }, ACT(LT, S_SELFB), + LT1, { '<' }, LT2, + LT1, { '=' }, ACT(LEQ, S_SELF), + LT2, { C_XX }, ACT(LSH, S_SELFB), + LT2, { '=' }, ACT(ASLSH, S_SELF), + + /* saw >, check >>, >>=, >= */ + GT1, { C_XX }, ACT(GT, S_SELFB), + GT1, { '>' }, GT2, + GT1, { '=' }, ACT(GEQ, S_SELF), + GT2, { C_XX }, ACT(RSH, S_SELFB), + GT2, { '=' }, ACT(ASRSH, S_SELF), + + /* = */ + ASG1, { C_XX }, ACT(ASGN, S_SELFB), + ASG1, { '=' }, ACT(EQ, S_SELF), + + /* ! */ + NOT1, { C_XX }, ACT(NOT, S_SELFB), + NOT1, { '=' }, ACT(NEQ, S_SELF), + + /* & */ + AND1, { C_XX }, ACT(AND, S_SELFB), + AND1, { '&' }, ACT(LAND, S_SELF), + AND1, { '=' }, ACT(ASAND, S_SELF), + + /* | */ + OR1, { C_XX }, ACT(OR, S_SELFB), + OR1, { '|' }, ACT(LOR, S_SELF), + OR1, { '=' }, ACT(ASOR, S_SELF), + + /* # */ + SHARP1, { C_XX }, ACT(SHARP, S_SELFB), + SHARP1, { '#' }, ACT(DSHARP, S_SELF), + + /* % */ + PCT1, { C_XX }, ACT(PCT, S_SELFB), + PCT1, { '=' }, ACT(ASPCT, S_SELF), + + /* * */ + STAR1, { C_XX }, ACT(STAR, S_SELFB), + STAR1, { '=' }, ACT(ASSTAR, S_SELF), + + /* ^ */ + CIRC1, { C_XX }, ACT(CIRC, S_SELFB), + CIRC1, { '=' }, ACT(ASCIRC, S_SELF), + + -1 +}; + +/* first index is char, second is state */ +/* increase #states to power of 2 to encourage use of shift */ +short bigfsm[256][MAXSTATE]; + +void +expandlex(void) +{ + /*const*/ struct fsm *fp; + int i, j, nstate; + + for (fp = fsm; fp->state>=0; fp++) { + for (i=0; fp->ch[i]; i++) { + nstate = fp->nextstate; + if (nstate >= S_SELF) + nstate = ~nstate; + switch (fp->ch[i]) { + + case C_XX: /* random characters */ + for (j=0; j<256; j++) + bigfsm[j][fp->state] = nstate; + continue; + case C_ALPH: + for (j=0; j<=256; j++) + if ('a'<=j&&j<='z' || 'A'<=j&&j<='Z' + || UTF2(j) || UTF3(j) || j=='_') + bigfsm[j][fp->state] = nstate; + continue; + case C_NUM: + for (j='0'; j<='9'; j++) + bigfsm[j][fp->state] = nstate; + continue; + default: + bigfsm[fp->ch[i]][fp->state] = nstate; + } + } + } + /* install special cases for ? (trigraphs), \ (splicing), runes, and EOB */ + for (i=0; i<MAXSTATE; i++) { + for (j=0; j<0xFF; j++) + if (j=='?' || j=='\\' || UTF2(j) || UTF3(j)) { + if (bigfsm[j][i]>0) + bigfsm[j][i] = ~bigfsm[j][i]; + bigfsm[j][i] &= ~QBSBIT; + } + bigfsm[EOB][i] = ~S_EOB; + if (bigfsm[EOFC][i]>=0) + bigfsm[EOFC][i] = ~S_EOF; + } +} + +void +fixlex(void) +{ + /* do C++ comments? */ + if (Cplusplus==0) + bigfsm['/'][COM1] = bigfsm['x'][COM1]; +} + +/* + * fill in a row of tokens from input, terminated by NL or END + * First token is put at trp->lp. + * Reset is non-zero when the input buffer can be "rewound." + * The value is a flag indicating that possible macros have + * been seen in the row. + */ +int +gettokens(Tokenrow *trp, int reset) +{ + register int c, state, oldstate; + register uchar *ip; + register Token *tp, *maxp; + int runelen; + Source *s = cursource; + int nmac = 0; + extern char outbuf[]; + + tp = trp->lp; + ip = s->inp; + if (reset) { + s->lineinc = 0; + if (ip>=s->inl) { /* nothing in buffer */ + s->inl = s->inb; + fillbuf(s); + ip = s->inp = s->inb; + } else if (ip >= s->inb+(3*s->ins/4)) { + memmove(s->inb, ip, 4+s->inl-ip); + s->inl = s->inb+(s->inl-ip); + ip = s->inp = s->inb; + } + } + maxp = &trp->bp[trp->max]; + runelen = 1; + for (;;) { + continue2: + if (tp>=maxp) { + trp->lp = tp; + tp = growtokenrow(trp); + maxp = &trp->bp[trp->max]; + } + tp->type = UNCLASS; + tp->hideset = 0; + tp->t = ip; + tp->wslen = 0; + tp->flag = 0; + state = START; + for (;;) { + oldstate = state; + c = *ip; + if ((state = bigfsm[c][state]) >= 0) { + ip += runelen; + runelen = 1; + continue; + } + state = ~state; + reswitch: + switch (state&0177) { + case S_SELF: + ip += runelen; + runelen = 1; + case S_SELFB: + tp->type = GETACT(state); + tp->len = ip - tp->t; + tp++; + goto continue2; + + case S_NAME: /* like S_SELFB but with nmac check */ + tp->type = NAME; + tp->len = ip - tp->t; + nmac |= quicklook(tp->t[0], tp->len>1?tp->t[1]:0); + tp++; + goto continue2; + + case S_WS: + tp->wslen = ip - tp->t; + tp->t = ip; + state = START; + continue; + + default: + if ((state&QBSBIT)==0) { + ip += runelen; + runelen = 1; + continue; + } + state &= ~QBSBIT; + s->inp = ip; + if (c=='?') { /* check trigraph */ + if (trigraph(s)) { + state = oldstate; + continue; + } + goto reswitch; + } + if (c=='\\') { /* line-folding */ + if (foldline(s)) { + s->lineinc++; + state = oldstate; + continue; + } + goto reswitch; + } + if (UTF2(c)) { + runelen = 2; + goto reswitch; + } + if (UTF3(c)) { + runelen = 3; + goto reswitch; + } + error(WARNING, "Lexical botch in cpp"); + ip += runelen; + runelen = 1; + continue; + + case S_EOB: + s->inp = ip; + fillbuf(cursource); + state = oldstate; + continue; + + case S_EOF: + tp->type = END; + tp->len = 0; + s->inp = ip; + if (tp!=trp->bp && (tp-1)->type!=NL && cursource->fd!=-1) + error(WARNING,"No newline at end of file"); + trp->lp = tp+1; + return nmac; + + case S_STNL: + error(ERROR, "Unterminated string or char const"); + case S_NL: + tp->t = ip; + tp->type = NL; + tp->len = 1; + tp->wslen = 0; + s->lineinc++; + s->inp = ip+1; + trp->lp = tp+1; + return nmac; + + case S_EOFSTR: + error(FATAL, "EOF in string or char constant"); + break; + + case S_COMNL: + s->lineinc++; + state = COM2; + ip += runelen; + runelen = 1; + if (ip >= s->inb+(7*s->ins/8)) { /* very long comment */ + memmove(tp->t, ip, 4+s->inl-ip); + s->inl -= ip-tp->t; + ip = tp->t+1; + } + continue; + + case S_EOFCOM: + error(WARNING, "EOF inside comment"); + --ip; + case S_COMMENT: + ++ip; + tp->t = ip; + tp->t[-1] = ' '; + tp->wslen = 1; + state = START; + continue; + } + break; + } + ip += runelen; + runelen = 1; + tp->len = ip - tp->t; + tp++; + } +} + +/* have seen ?; handle the trigraph it starts (if any) else 0 */ +int +trigraph(Source *s) +{ + int c; + + while (s->inp+2 >= s->inl && fillbuf(s)!=EOF) + ; + if (s->inp[1]!='?') + return 0; + c = 0; + switch(s->inp[2]) { + case '=': + c = '#'; break; + case '(': + c = '['; break; + case '/': + c = '\\'; break; + case ')': + c = ']'; break; + case '\'': + c = '^'; break; + case '<': + c = '{'; break; + case '!': + c = '|'; break; + case '>': + c = '}'; break; + case '-': + c = '~'; break; + } + if (c) { + *s->inp = c; + memmove(s->inp+1, s->inp+3, s->inl-s->inp+2); + s->inl -= 2; + } + return c; +} + +int +foldline(Source *s) +{ + int ncr = 0; + +recheck: + while (s->inp+1 >= s->inl && fillbuf(s)!=EOF) + ; + if (s->inp[ncr+1] == '\r') { /* nonstandardly, ignore CR before line-folding */ + ncr++; + goto recheck; + } + if (s->inp[ncr+1] == '\n') { + memmove(s->inp, s->inp+2+ncr, s->inl-s->inp+3-ncr); + s->inl -= 2+ncr; + return 1; + } + return 0; +} + +int +fillbuf(Source *s) +{ + int n; + + while((char *)s->inl+s->ins/8 > (char *)s->inb+s->ins) { + int l = s->inl - s->inb; + int p = s->inp - s->inb; + if(l < 0) + error(FATAL, "negative end of input!?"); + if(p < 0) + error(FATAL, "negative input pointer!?"); + /* double the buffer size and try again */ + s->ins *= 2; + s->inb = dorealloc(s->inb, s->ins); + s->inl = s->inb + l; + s->inp = s->inb + p; + } + if (s->fd<0 || (n=read(s->fd, (char *)s->inl, s->ins/8)) <= 0) + n = 0; + if ((*s->inp&0xff) == EOB) /* sentinel character appears in input */ + *s->inp = EOFC; + s->inl += n; + s->inl[0] = s->inl[1]= s->inl[2]= s->inl[3] = EOB; + if (n==0) { + s->inl[0] = s->inl[1]= s->inl[2]= s->inl[3] = EOFC; + return EOF; + } + return 0; +} + +/* + * Push down to new source of characters. + * If fd>0 and str==NULL, then from a file `name'; + * if fd==-1 and str, then from the string. + */ +Source * +setsource(char *name, int fd, char *str) +{ + Source *s = new(Source); + int len; + + s->line = 1; + s->lineinc = 0; + s->fd = fd; + s->filename = name; + s->next = cursource; + s->ifdepth = 0; + cursource = s; + /* slop at right for EOB */ + if (str) { + len = strlen(str); + s->inb = domalloc(len+4); + s->inp = s->inb; + strncpy((char *)s->inp, str, len); + } else { + Dir *d; + int junk; + ulong length = 0; + d = dirfstat(fd); + if (d != nil) { + length = d->length; + free(d); + } + junk = length; + if (junk<INS) + junk = INS; + s->inb = domalloc((junk)+4); + s->inp = s->inb; + len = 0; + } + + s->ins = INS; + s->inl = s->inp+len; + s->inl[0] = s->inl[1] = EOB; + return s; +} + +void +unsetsource(void) +{ + Source *s = cursource; + + if (s->fd>=0) { + close(s->fd); + dofree(s->inb); + } + cursource = s->next; + dofree(s); +} |