mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-12-01 00:21:43 +00:00
43abfba723
re2c instead of "Linking X". - Updated lemon and re2c to the latest versions and ported dehsupp to use them for code generation. (Xlatcc is next.) - Added function level linking for Makefile.mingw. SVN r144 (trunk)
393 lines
5.3 KiB
C++
393 lines
5.3 KiB
C++
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include "globals.h"
|
|
#include "substr.h"
|
|
#include "dfa.h"
|
|
|
|
namespace re2c
|
|
{
|
|
|
|
void prtChOrHex(std::ostream& o, uint c, bool useTalx)
|
|
{
|
|
int oc = (int)(re2c::wFlag || !useTalx ? c : re2c::talx[c]);
|
|
|
|
if ((oc < 256) && isprint(oc))
|
|
{
|
|
o << '\'';
|
|
prtCh(o, oc);
|
|
o << '\'';
|
|
}
|
|
else
|
|
{
|
|
prtHex(o, c);
|
|
}
|
|
}
|
|
|
|
void prtHex(std::ostream& o, uint c, bool useTalx)
|
|
{
|
|
int oc = (int)(re2c::wFlag || !useTalx ? c : re2c::talx[c]);
|
|
|
|
if (re2c::wFlag)
|
|
{
|
|
o << "0x"
|
|
<< hexCh(oc >> 12)
|
|
<< hexCh(oc >> 8)
|
|
<< hexCh(oc >> 4)
|
|
<< hexCh(oc);
|
|
}
|
|
else
|
|
{
|
|
o << "0x"
|
|
<< hexCh(oc >> 4)
|
|
<< hexCh(oc);
|
|
}
|
|
}
|
|
|
|
void prtCh(std::ostream& o, uint c, bool useTalx)
|
|
{
|
|
int oc = (int)(re2c::wFlag || !useTalx ? c : re2c::talx[c]);
|
|
|
|
switch (oc)
|
|
{
|
|
case '\'':
|
|
o << "\\'";
|
|
break;
|
|
|
|
case '\n':
|
|
o << "\\n";
|
|
break;
|
|
|
|
case '\t':
|
|
o << "\\t";
|
|
break;
|
|
|
|
case '\v':
|
|
o << "\\v";
|
|
break;
|
|
|
|
case '\b':
|
|
o << "\\b";
|
|
break;
|
|
|
|
case '\r':
|
|
o << "\\r";
|
|
break;
|
|
|
|
case '\f':
|
|
o << "\\f";
|
|
break;
|
|
|
|
case '\a':
|
|
o << "\\a";
|
|
break;
|
|
|
|
case '\\':
|
|
o << "\\\\";
|
|
break;
|
|
|
|
default:
|
|
|
|
if ((oc < 256) && isprint(oc))
|
|
{
|
|
o << (char) oc;
|
|
}
|
|
else if (re2c::wFlag)
|
|
{
|
|
o << "0x"
|
|
<< hexCh(oc >> 12)
|
|
<< hexCh(oc >> 8)
|
|
<< hexCh(oc >> 4)
|
|
<< hexCh(oc);
|
|
}
|
|
else
|
|
{
|
|
o << '\\' << octCh(oc / 64) << octCh(oc / 8) << octCh(oc);
|
|
}
|
|
}
|
|
}
|
|
|
|
void printSpan(std::ostream& o, uint lb, uint ub)
|
|
{
|
|
if (lb > ub)
|
|
{
|
|
o << "*";
|
|
}
|
|
|
|
o << "[";
|
|
|
|
if ((ub - lb) == 1)
|
|
{
|
|
prtCh(o, lb);
|
|
}
|
|
else
|
|
{
|
|
prtCh(o, lb);
|
|
o << "-";
|
|
prtCh(o, ub - 1);
|
|
}
|
|
|
|
o << "]";
|
|
}
|
|
|
|
uint Span::show(std::ostream &o, uint lb) const
|
|
{
|
|
if (to)
|
|
{
|
|
printSpan(o, lb, ub);
|
|
o << " " << to->label << "; ";
|
|
}
|
|
|
|
return ub;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream &o, const State &s)
|
|
{
|
|
o << "state " << s.label;
|
|
|
|
if (s.rule)
|
|
{
|
|
o << " accepts " << s.rule->accept;
|
|
}
|
|
|
|
o << "\n";
|
|
|
|
uint lb = 0;
|
|
|
|
for (uint i = 0; i < s.go.nSpans; ++i)
|
|
{
|
|
lb = s.go.span[i].show(o, lb);
|
|
}
|
|
|
|
return o;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream &o, const DFA &dfa)
|
|
{
|
|
for (State *s = dfa.head; s; s = s->next)
|
|
{
|
|
o << s << "\n\n";
|
|
}
|
|
|
|
return o;
|
|
}
|
|
|
|
State::State()
|
|
: label(0)
|
|
, rule(NULL)
|
|
, next(0)
|
|
, link(NULL)
|
|
, depth(0)
|
|
, kCount(0)
|
|
, kernel(NULL)
|
|
, isPreCtxt(false)
|
|
, isBase(false)
|
|
, go()
|
|
, action(NULL)
|
|
{
|
|
}
|
|
|
|
State::~State()
|
|
{
|
|
delete [] kernel;
|
|
delete [] go.span;
|
|
}
|
|
|
|
static Ins **closure(Ins **cP, Ins *i)
|
|
{
|
|
while (!isMarked(i))
|
|
{
|
|
mark(i);
|
|
*(cP++) = i;
|
|
|
|
if (i->i.tag == FORK)
|
|
{
|
|
cP = closure(cP, i + 1);
|
|
i = (Ins*) i->i.link;
|
|
}
|
|
else if (i->i.tag == GOTO || i->i.tag == CTXT)
|
|
{
|
|
i = (Ins*) i->i.link;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
return cP;
|
|
}
|
|
|
|
struct GoTo
|
|
{
|
|
Char ch;
|
|
void *to;
|
|
};
|
|
|
|
DFA::DFA(Ins *ins, uint ni, uint lb, uint ub, Char *rep)
|
|
: lbChar(lb)
|
|
, ubChar(ub)
|
|
, nStates(0)
|
|
, head(NULL)
|
|
, tail(&head)
|
|
, toDo(NULL)
|
|
{
|
|
Ins **work = new Ins * [ni + 1];
|
|
uint nc = ub - lb;
|
|
GoTo *goTo = new GoTo[nc];
|
|
Span *span = new Span[nc];
|
|
memset((char*) goTo, 0, nc*sizeof(GoTo));
|
|
findState(work, closure(work, &ins[0]) - work);
|
|
|
|
while (toDo)
|
|
{
|
|
State *s = toDo;
|
|
toDo = s->link;
|
|
|
|
Ins **cP, **iP, *i;
|
|
uint nGoTos = 0;
|
|
uint j;
|
|
|
|
s->rule = NULL;
|
|
|
|
for (iP = s->kernel; (i = *iP); ++iP)
|
|
{
|
|
if (i->i.tag == CHAR)
|
|
{
|
|
for (Ins *j = i + 1; j < (Ins*) i->i.link; ++j)
|
|
{
|
|
if (!(j->c.link = goTo[j->c.value - lb].to))
|
|
goTo[nGoTos++].ch = j->c.value;
|
|
|
|
goTo[j->c.value - lb].to = j;
|
|
}
|
|
}
|
|
else if (i->i.tag == TERM)
|
|
{
|
|
if (!s->rule || ((RuleOp*) i->i.link)->accept < s->rule->accept)
|
|
s->rule = (RuleOp*) i->i.link;
|
|
}
|
|
else if (i->i.tag == CTXT)
|
|
{
|
|
s->isPreCtxt = true;
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < nGoTos; ++j)
|
|
{
|
|
GoTo *go = &goTo[goTo[j].ch - lb];
|
|
i = (Ins*) go->to;
|
|
|
|
for (cP = work; i; i = (Ins*) i->c.link)
|
|
cP = closure(cP, i + i->c.bump);
|
|
|
|
go->to = findState(work, cP - work);
|
|
}
|
|
|
|
s->go.nSpans = 0;
|
|
|
|
for (j = 0; j < nc;)
|
|
{
|
|
State *to = (State*) goTo[rep[j]].to;
|
|
|
|
while (++j < nc && goTo[rep[j]].to == to) ;
|
|
|
|
span[s->go.nSpans].ub = lb + j;
|
|
|
|
span[s->go.nSpans].to = to;
|
|
|
|
s->go.nSpans++;
|
|
}
|
|
|
|
for (j = nGoTos; j-- > 0;)
|
|
goTo[goTo[j].ch - lb].to = NULL;
|
|
|
|
s->go.span = new Span[s->go.nSpans];
|
|
|
|
memcpy((char*) s->go.span, (char*) span, s->go.nSpans*sizeof(Span));
|
|
|
|
(void) new Match(s);
|
|
|
|
}
|
|
|
|
delete [] work;
|
|
delete [] goTo;
|
|
delete [] span;
|
|
}
|
|
|
|
DFA::~DFA()
|
|
{
|
|
State *s;
|
|
|
|
while ((s = head))
|
|
{
|
|
head = s->next;
|
|
delete s;
|
|
}
|
|
}
|
|
|
|
void DFA::addState(State **a, State *s)
|
|
{
|
|
s->label = nStates++;
|
|
s->next = *a;
|
|
*a = s;
|
|
|
|
if (a == tail)
|
|
tail = &s->next;
|
|
}
|
|
|
|
State *DFA::findState(Ins **kernel, uint kCount)
|
|
{
|
|
Ins **cP, **iP, *i;
|
|
State *s;
|
|
|
|
kernel[kCount] = NULL;
|
|
|
|
cP = kernel;
|
|
|
|
for (iP = kernel; (i = *iP); ++iP)
|
|
{
|
|
if (i->i.tag == CHAR || i->i.tag == TERM || i->i.tag == CTXT)
|
|
{
|
|
*cP++ = i;
|
|
}
|
|
else
|
|
{
|
|
unmark(i);
|
|
}
|
|
}
|
|
|
|
kCount = cP - kernel;
|
|
kernel[kCount] = NULL;
|
|
|
|
for (s = head; s; s = s->next)
|
|
{
|
|
if (s->kCount == kCount)
|
|
{
|
|
for (iP = s->kernel; (i = *iP); ++iP)
|
|
if (!isMarked(i))
|
|
goto nextState;
|
|
|
|
goto unmarkAll;
|
|
}
|
|
|
|
nextState:
|
|
;
|
|
}
|
|
|
|
s = new State;
|
|
addState(tail, s);
|
|
s->kCount = kCount;
|
|
s->kernel = new Ins * [kCount + 1];
|
|
memcpy(s->kernel, kernel, (kCount + 1)*sizeof(Ins*));
|
|
s->link = toDo;
|
|
toDo = s;
|
|
|
|
unmarkAll:
|
|
|
|
for (iP = kernel; (i = *iP); ++iP)
|
|
unmark(i);
|
|
|
|
return s;
|
|
}
|
|
|
|
} // end namespace re2c
|
|
|