blob: 16509de2a9185d2597dd1458698df4413ebbbcfb [file] [log] [blame]
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "tools/re2c/globals.h"
#include "tools/re2c/substr.h"
#include "tools/re2c/dfa.h"
#define octCh(c) ('0' + c%8)
void prtCh(FILE *o, unsigned char c){
unsigned char oc = talx[c];
switch(oc){
case '\'': fputs("\\'", o); break;
case '\n': fputs("\\n", o); break;
case '\t': fputs("\\t", o); break;
case '\v': fputs("\\v", o); break;
case '\b': fputs("\\b", o); break;
case '\r': fputs("\\r", o); break;
case '\f': fputs("\\f", o); break;
case '\a': fputs("\\a", o); break;
case '\\': fputs("\\\\", o); break;
default:
if(isprint(oc))
fputc(oc, o);
else
fprintf(o, "\\%c%c%c", octCh(c/64), octCh(c/8), octCh(c));
}
}
void printSpan(FILE *o, unsigned int lb, unsigned int ub){
if(lb > ub)
fputc('*', o);
fputc('[', o);
if((ub - lb) == 1){
prtCh(o, lb);
} else {
prtCh(o, lb);
fputc('-', o);
prtCh(o, ub-1);
}
fputc(']', o);
}
unsigned int
Span_show(Span *s, FILE *o, unsigned int lb)
{
if(s->to){
printSpan(o, lb, s->ub);
fprintf(o, " %u; ", s->to->label);
}
return s->ub;
}
void
State_out(FILE *o, const State *s){
unsigned int lb, i;
fprintf(o, "state %u", s->label);
if(s->rule)
fprintf(o, " accepts %u", s->rule->d.RuleOp.accept);
fputs("\n", o); oline++;
lb = 0;
for(i = 0; i < s->go.nSpans; ++i)
lb = Span_show(&s->go.span[i], o, lb);
}
void
DFA_out(FILE *o, const DFA *dfa){
State *s;
for(s = dfa->head; s; s = s->next) {
State_out(o, s);
fputs("\n\n", o); oline+=2;
}
}
State *
State_new(void)
{
State *s = malloc(sizeof(State));
s->label = 0;
s->rule = NULL;
s->next = NULL;
s->link = NULL;
s->depth = 0;
s->kCount = 0;
s->kernel = NULL;
s->isBase = 0;
s->action = NULL;
s->go.nSpans = 0;
s->go.span = NULL;
return s;
}
void
State_delete(State *s)
{
if (s->kernel)
free(s->kernel);
if (s->go.span)
free(s->go.span);
free(s);
}
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 = (Ins*) i->i.link;
} else
break;
}
return cP;
}
typedef struct GoTo {
Char ch;
void *to;
} GoTo;
DFA *
DFA_new(Ins *ins, unsigned int ni, unsigned int lb, unsigned int ub, Char *rep)
{
DFA *d = malloc(sizeof(DFA));
Ins **work = malloc(sizeof(Ins*)*(ni+1));
unsigned int nc = ub - lb;
GoTo *goTo = malloc(sizeof(GoTo)*nc);
Span *span = malloc(sizeof(Span)*nc);
d->lbChar = lb;
d->ubChar = ub;
memset((char*) goTo, 0, nc*sizeof(GoTo));
d->tail = &d->head;
d->head = NULL;
d->nStates = 0;
d->toDo = NULL;
DFA_findState(d, work, closure(work, &ins[0]) - work);
while(d->toDo){
State *s = d->toDo;
Ins **cP, **iP, *i;
unsigned int nGoTos = 0;
unsigned int j;
d->toDo = s->link;
s->rule = NULL;
for(iP = s->kernel; (i = *iP); ++iP){
if(i->i.tag == CHAR){
Ins *j2;
for(j2 = i + 1; j2 < (Ins*) i->i.link; ++j2){
if(!(j2->c.link = goTo[j2->c.value - lb].to))
goTo[nGoTos++].ch = j2->c.value;
goTo[j2->c.value - lb].to = j2;
}
} else if(i->i.tag == TERM){
if(!s->rule || ((RegExp *)i->i.link)->d.RuleOp.accept < s->rule->d.RuleOp.accept)
s->rule = (RegExp *)i->i.link;
}
}
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 = DFA_findState(d, 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 = malloc(sizeof(Span)*s->go.nSpans);
memcpy((char*) s->go.span, (char*) span, s->go.nSpans*sizeof(Span));
Action_new_Match(s);
}
free(work);
free(goTo);
free(span);
return d;
}
void
DFA_delete(DFA *d){
State *s;
while((s = d->head)){
d->head = s->next;
State_delete(s);
}
}
void DFA_addState(DFA *d, State **a, State *s){
s->label = d->nStates++;
s->next = *a;
*a = s;
if(a == d->tail)
d->tail = &s->next;
}
State *DFA_findState(DFA *d, Ins **kernel, unsigned int 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){
*cP++ = i;
} else {
unmark(i);
}
}
kCount = cP - kernel;
kernel[kCount] = NULL;
for(s = d->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 = State_new();
DFA_addState(d, d->tail, s);
s->kCount = kCount;
s->kernel = malloc(sizeof(Ins*)*(kCount+1));
memcpy(s->kernel, kernel, (kCount+1)*sizeof(Ins*));
s->link = d->toDo;
d->toDo = s;
unmarkAll:
for(iP = kernel; (i = *iP); ++iP)
unmark(i);
return s;
}