/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project .
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2 . 0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice :
*
* Licensed to the Apache Software Foundation ( ASF ) under one or more
* contributor license agreements . See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership . The ASF licenses this file to you under the Apache
* License , Version 2 . 0 ( the " License " ) ; you may not use this file
* except in compliance with the License . You may obtain a copy of
* the License at http : //www.apache.org/licenses/LICENSE-2.0 .
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if (defined (_WIN32) || defined (__IBMC__))
#include <io.h>
#else
#include <unistd.h>
#endif
#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
* 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 )&0 x1ff)
/* character classes */
#define C_ALPH 1
#define C_NUM 2
#define C_XX 3
enum state
{
START = 0 , NUM1, NUM2, NUM3, ID1, ST1, ST2, ST3, COM1, COM2, COM3, COM4,
CC1, CC2, WS1, PLUS1, MINUS1, STAR1, 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
};
struct fsm
{
int state; /* if in this state */
uchar ch[4 ]; /* and see one of these characters */
int nextstate; /* enter this state if +ve */
};
static const struct fsm fsm[] = {
/* start state */
{START, {C_XX}, ACT(UNCLASS, S_SELF)},
{START, {' ' , '\t' , '\v' }, 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 / followed by *, 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},
/* // 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' , ' ' }, 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 , "" , 0 }
};
/* first index is char, second is state */
/* increase #states to power of 2 to encourage use of shift */
static 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] = (short ) nstate;
continue ;
case C_ALPH:
for (j = 0 ; j < 256 ; j++)
if (('a' <= j && j <= 'z' ) || ('A' <= j && j <= 'Z' )
|| j == '_' )
bigfsm[j][fp->state] = (short ) nstate;
continue ;
case C_NUM:
for (j = '0' ; j <= '9' ; j++)
bigfsm[j][fp->state] = (short ) nstate;
continue ;
default :
bigfsm[fp->ch[i]][fp->state] = (short ) nstate;
}
}
}
/*
* install special cases for ? ( trigraphs ) , \ ( splicing ) , runes , and
* EOB
*/
for (i = 0 ; i < MAXSTATE; i++)
{
for (j = 0 ; j < 0 xFF; j++)
if (j == '?' || j == '\\' || j == '\n' || j == '\r' )
{
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 ) || (Cflag != 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)
{
int c, state, oldstate;
uchar *ip;
Token *tp, *maxp;
int runelen;
Source *s = cursource;
int nmac = 0 ;
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 * 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);
// coverity[overrun-local : FALSE] - a multiple of trp->max is allocated, not trp->max itself
maxp = &trp->bp[trp->max];
}
tp->type = UNCLASS;
tp->t = ip;
tp->wslen = 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 ;
/*fall-through*/
case S_SELFB:
tp->type = (unsigned char ) 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 == '\n' )
{
while (s->inp + 1 >= s->inl && fillbuf(s) != EOF);
if (s->inp[1 ] == '\r' )
{
memmove(s->inp + 1 , s->inp + 2 , s->inl - s->inp + 2 );
s->inl -= 1 ;
}
goto reswitch;
}
if (c == '\r' )
{
while (s->inp + 1 >= s->inl && fillbuf(s) != EOF);
if (s->inp[1 ] == '\n' )
{
memmove(s->inp, s->inp + 1 , s->inl - s->inp + 1 );
s->inl -= 1 ;
}
else
*s->inp = '\n' ;
state = oldstate;
continue ;
}
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;
}
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" );
/* fall through */
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 ;
continue ;
case S_EOFCOM:
error(WARNING, "EOF inside comment" );
--ip;
/* fall through */
case S_COMMENT:
if (!Cflag)
{
tp->t = ++ip;
tp->t[-1 ] = ' ' ;
tp->wslen = 1 ;
state = START;
continue ;
}
else
{
runelen = 1 ;
s->lineinc = 0 ;
tp->type = COMMENT;
}
}
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)
{
uchar 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 n = 1 ;
/* skip pending white spaces */
while ((s->inp[n] == ' ' ) || (s->inp[n] == '\t' ))
{
n++;
if ((s->inp + n >= s->inl) && (fillbuf(s) == EOF))
break ;
}
/* refill buffer */
while (s->inp + (n + 1 ) >= s->inl && fillbuf(s) != EOF);
/* skip DOS line ends */
if (((s->inp[n] == '\r' ) && (s->inp[n+1 ] == '\n' )) ||
((s->inp[n] == '\n' ) && (s->inp[n+1 ] == '\r' )))
n++;
if ((s->inp[n] == '\n' ) || (s->inp[n] == '\r' ))
{
memmove(s->inp, s->inp + n + 1 , s->inl - s->inp + n + 2 );
s->inl -= n + 1 ;
return 1 ;
}
return 0 ;
}
int
fillbuf(Source * s)
{
int n = 0 ;
if (s->fd >= 0 )
{
n = read(s->fd, (char *) s->inl, INS / 8 );
if (n <= 0 )
n = 0 ;
}
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 path, int fd, char const *str, int wrap)
{
Source *s = new (Source);
size_t len;
s->line = 1 ;
s->lineinc = 0 ;
s->fd = fd;
s->filename = name;
s->next = cursource;
s->ifdepth = 0 ;
s->pathdepth = path;
s->wrap = wrap;
cursource = s;
if (s->wrap)
genwrap(0 );
/* slop at right for EOB */
if (str)
{
len = strlen(str);
s->inb = domalloc(len + 4 );
s->inp = s->inb;
memcpy((char *) s->inp, str, len);
}
else
{
s->inb = domalloc(INS + 4 );
s->inp = s->inb;
len = 0 ;
}
s->inl = s->inp + len;
s->inl[0 ] = s->inl[1 ] = EOB;
return s;
}
void
unsetsource(void )
{
Source *s = cursource;
if (s->wrap)
genwrap(1 );
if (s->fd >= 0 )
{
close(s->fd);
dofree(s->inb);
}
cursource = s->next;
dofree(s);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 in Prozent C=95 H=95 G=94
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-09-27)
¤
*© Formatika GbR, Deutschland