mirror of https://github.com/yasm/yasm.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
5.0 KiB
251 lines
5.0 KiB
#include <config.h> |
|
|
|
#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, uchar c){ |
|
uchar 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, uint lb, uint 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); |
|
} |
|
|
|
uint |
|
Span_show(Span *s, FILE *o, uint 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){ |
|
uint lb, i; |
|
fprintf(o, "state %u", s->label); |
|
if(s->rule) |
|
fprintf(o, " accepts %u", s->rule->d.RuleOp.accept); |
|
fputs("\n", o); |
|
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); |
|
} |
|
} |
|
|
|
State * |
|
State_new(void) |
|
{ |
|
State *s = malloc(sizeof(State)); |
|
s->rule = NULL; |
|
s->link = NULL; |
|
s->kCount = 0; |
|
s->kernel = NULL; |
|
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, uint ni, uint lb, uint ub, Char *rep) |
|
{ |
|
DFA *d = malloc(sizeof(DFA)); |
|
Ins **work = malloc(sizeof(Ins*)*(ni+1)); |
|
uint 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; |
|
uint nGoTos = 0; |
|
uint j; |
|
|
|
d->toDo = s->link; |
|
s->rule = NULL; |
|
for(iP = s->kernel; (i = *iP); ++iP){ |
|
if(i->i.tag == CHAR){ |
|
Ins *j; |
|
for(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 || ((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, 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){ |
|
*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; |
|
}
|
|
|