From bcf633273c9b17c1985df17b526dab97c1bd9395 Mon Sep 17 00:00:00 2001 From: nuffer Date: Sat, 13 Dec 2003 04:58:19 +0000 Subject: [PATCH] Initial revision --- CHANGELOG | 18 ++ Makefile | 76 +++++ NO_WARRANTY | 2 + README | 153 ++++++++++ actions.cc | 505 +++++++++++++++++++++++++++++++ basics.h | 9 + bootstrap/parser.cc | 531 ++++++++++++++++++++++++++++++++ bootstrap/re2c.man | 660 ++++++++++++++++++++++++++++++++++++++++ bootstrap/scanner.cc | 470 +++++++++++++++++++++++++++++ bootstrap/y.tab.h | 12 + code.cc | 665 +++++++++++++++++++++++++++++++++++++++++ dfa.cc | 222 ++++++++++++++ dfa.h | 149 +++++++++ doc/loplas.ps.gz | Bin 0 -> 69079 bytes doc/sample.bib | 48 +++ examples/basemmap.c | 26 ++ examples/c.re | 272 +++++++++++++++++ examples/cmmap.re | 267 +++++++++++++++++ examples/cnokw.re | 239 +++++++++++++++ examples/cunroll.re | 258 ++++++++++++++++ examples/modula.re | 202 +++++++++++++ examples/rexx/README | 1 + examples/rexx/rexx.l | 319 ++++++++++++++++++++ examples/rexx/scanio.c | 41 +++ examples/sample.re | 7 + examples/simple.re | 13 + globals.h | 15 + ins.h | 41 +++ main.cc | 54 ++++ parser.cc | 531 ++++++++++++++++++++++++++++++++ parser.h | 20 ++ parser.y | 163 ++++++++++ re.h | 178 +++++++++++ re2c.1 | 536 +++++++++++++++++++++++++++++++++ scanner.cc | 470 +++++++++++++++++++++++++++++ scanner.h | 30 ++ scanner.re | 173 +++++++++++ substr.cc | 30 ++ substr.h | 45 +++ token.h | 18 ++ translate.cc | 61 ++++ y.tab.h | 12 + 42 files changed, 7542 insertions(+) create mode 100644 CHANGELOG create mode 100644 Makefile create mode 100644 NO_WARRANTY create mode 100644 README create mode 100644 actions.cc create mode 100644 basics.h create mode 100644 bootstrap/parser.cc create mode 100644 bootstrap/re2c.man create mode 100644 bootstrap/scanner.cc create mode 100644 bootstrap/y.tab.h create mode 100644 code.cc create mode 100644 dfa.cc create mode 100644 dfa.h create mode 100644 doc/loplas.ps.gz create mode 100644 doc/sample.bib create mode 100644 examples/basemmap.c create mode 100644 examples/c.re create mode 100644 examples/cmmap.re create mode 100644 examples/cnokw.re create mode 100644 examples/cunroll.re create mode 100644 examples/modula.re create mode 100644 examples/rexx/README create mode 100644 examples/rexx/rexx.l create mode 100644 examples/rexx/scanio.c create mode 100644 examples/sample.re create mode 100644 examples/simple.re create mode 100644 globals.h create mode 100644 ins.h create mode 100644 main.cc create mode 100644 parser.cc create mode 100644 parser.h create mode 100644 parser.y create mode 100644 re.h create mode 100644 re2c.1 create mode 100644 scanner.cc create mode 100644 scanner.h create mode 100644 scanner.re create mode 100644 substr.cc create mode 100644 substr.h create mode 100644 token.h create mode 100644 translate.cc create mode 100644 y.tab.h diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 00000000..06090aa6 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,18 @@ +re2c +---- + +Version 0.9.1 +------------- + +- removed rcs comments in source files + +Version 0.9 +----------- + +- redistribution based on version 0.5 +- added parentheses to assignment expressions in 'if' statements +- rearranged class members to match initialization order +- substr fix +- use array delete [] when necessary +- other minor fixes for subduing compiler warnings + diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..b392b0f5 --- /dev/null +++ b/Makefile @@ -0,0 +1,76 @@ +# $Log$ +# Revision 1.1 2003/12/13 04:58:19 nuffer +# Initial revision +# +#Revision 1.1 1994/04/08 16:30:37 peter +#Initial revision +# + +BIN = /usr/local/bin +MAN = /usr/local/man + +%.o : %.cc ; $(CC) -o $@ $(CFLAGS) -c $< +%.cc : %.y ; $(YACC) $(YFLAGS) $<; mv $(YTAB).c $@ +%.cc : %.l ; $(LEX) $(LFLAGS) $<; mv $(LEXYY).c $@ + +%.cc: %.re + re2c -s $< >$@ + +SOURCES = code.cc dfa.cc main.cc parser.y actions.cc scanner.re substr.cc\ + translate.cc +OBJS = code.o dfa.o main.o parser.o actions.o scanner.o substr.o\ + translate.o + +CC = g++ +CFLAGS = -O2 -Wall -I. -Wno-unused -Wno-parentheses +YFLAGS = -d +LDFLAGS = + +default: re2c + +clean: + rm -f *.o *.s y.tab.c y.tab.h scanner.cc parser.cc .version version.h re2c + +parser.cc: parser.y + yacc -d parser.y + mv -f y.tab.c parser.cc + +re2c: $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAGS) -lstdc++ + +.version: README + egrep "^Version" README | sed 's/Version //' > .version + +version.h: .version + echo "#define RE2C_VERSION" `cat .version` > version.h + +install: re2c + install -d $(BIN) + install -s re2c $(BIN) + install -d $(MAN)/man1 + install -m 0644 re2c.1 $(MAN)/man1 + +dist: re2c scanner.cc .version + mkdir re2c-`cat .version` + cp -P `p4 files ... | sed s/\\\\/\\\\/depot\\\\/home\\\\/re2c\\\\/// | sed '/- delete/d' | sed s/#.*$$//` re2c-`cat .version`/ + tar zcf re2c-`cat .version`.tar.gz re2c-`cat .version`/ + rm -rf re2c-`cat .version` + +# +# generated with "gcc -I. -MM -x c++ *.cc *.y *.re" +# and edited by hand +# +actions.o : actions.cc globals.h basics.h parser.h scanner.h \ + token.h substr.h re.h ins.h dfa.h +code.o : code.cc substr.h basics.h globals.h dfa.h re.h token.h \ + ins.h +dfa.o : dfa.cc globals.h basics.h substr.h dfa.h re.h token.h \ + ins.h +main.o : main.cc globals.h basics.h parser.h scanner.h token.h \ + substr.h re.h ins.h dfa.h version.h +substr.o : substr.cc substr.h basics.h +translate.o : translate.cc globals.h basics.h +scanner.o : scanner.re scanner.h token.h substr.h basics.h \ + parser.h re.h ins.h ./parser.o +parser.o : parser.y globals.h basics.h parser.h scanner.h token.h \ + substr.h re.h ins.h diff --git a/NO_WARRANTY b/NO_WARRANTY new file mode 100644 index 00000000..885a13d0 --- /dev/null +++ b/NO_WARRANTY @@ -0,0 +1,2 @@ +re2c is distributed with no warranty whatever. The author and any other +contributors take no responsibility for the consequences of its use. diff --git a/README b/README new file mode 100644 index 00000000..a16c4712 --- /dev/null +++ b/README @@ -0,0 +1,153 @@ +re2c +---- + +Version 0.9.1 +Originally written by Peter Bumbulis (peter@csg.uwaterloo.ca) +Currently maintained by Brian Young (bayoung@acm.org) + +The re2c distribution can be found at: + + http://www.tildeslash.org/re2c/index.html + +The source distribution is available from: + + http://www.tildeslash.org/re2c/re2c-0.9.1.tar.gz + +This distribution is a cleaned up version of the 0.5 release +maintained by me (Brian Young). Several bugs were fixed as well +as code cleanup for warning free compilation. It has been developed +and tested with egcs 1.0.2 and gcc 2.7.2.3 on Linux x86. Peter +Bumbulis' original release can be found at: + + ftp://csg.uwaterloo.ca/pub/peter/re2c.0.5.tar.gz + +re2c is a great tool for writing fast and flexible lexers. It has +served many people well for many years and it deserves to be +maintained more actively. re2c is on the order of 2-3 times faster +than a flex based scanner, and its input model is much more +flexible. + +Patches and requests for features will be entertained. Areas of +particular interest to me are porting (a Solaris and an NT +version will be forthcoming) and wide character support. Note +that the code is already quite portable and should be buildable +on any platform with minor makefile changes. + +Peter's original version 0.5 ANNOUNCE and README follows. + +Brian + +-- + +re2c is a tool for generating C-based recognizers from regular +expressions. re2c-based scanners are efficient: for programming +languages, given similar specifications, an re2c-based scanner is +typically almost twice as fast as a flex-based scanner with little or no +increase in size (possibly a decrease on cisc architectures). Indeed, +re2c-based scanners are quite competitive with hand-crafted ones. + +Unlike flex, re2c does not generate complete scanners: the user must +supply some interface code. While this code is not bulky (about 50-100 +lines for a flex-like scanner; see the man page and examples in the +distribution) careful coding is required for efficiency (and +correctness). One advantage of this arrangement is that the generated +code is not tied to any particular input model. For example, re2c +generated code can be used to scan data from a null-byte terminated +buffer as illustrated below. + +Given the following source + + #define NULL ((char*) 0) + char *scan(char *p){ + char *q; + #define YYCTYPE char + #define YYCURSOR p + #define YYLIMIT p + #define YYMARKER q + #define YYFILL(n) + /*!re2c + [0-9]+ {return YYCURSOR;} + [\000-\377] {return NULL;} + */ + } + +re2c will generate + + /* Generated by re2c on Sat Apr 16 11:40:58 1994 */ + #line 1 "simple.re" + #define NULL ((char*) 0) + char *scan(char *p){ + char *q; + #define YYCTYPE char + #define YYCURSOR p + #define YYLIMIT p + #define YYMARKER q + #define YYFILL(n) + { + YYCTYPE yych; + unsigned int yyaccept; + goto yy0; + yy1: ++YYCURSOR; + yy0: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= '/') goto yy4; + if(yych >= ':') goto yy4; + yy2: yych = *++YYCURSOR; + goto yy7; + yy3: + #line 10 + {return YYCURSOR;} + yy4: yych = *++YYCURSOR; + yy5: + #line 11 + {return NULL;} + yy6: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + yy7: if(yych <= '/') goto yy3; + if(yych <= '9') goto yy6; + goto yy3; + } + #line 12 + + } + +Note that most compilers will perform dead-code elimination to remove +all YYCURSOR, YYLIMIT comparisions. + +re2c was developed for a particular project (constructing a fast REXX +scanner of all things!) and so while it has some rough edges, it should +be quite usable. More information about re2c can be found in the +(admittedly skimpy) man page; the algorithms and heuristics used are +described in an upcoming LOPLAS article (included in the distribution). +Probably the best way to find out more about re2c is to try the supplied +examples. re2c is written in C++, and is currently being developed +under Linux using gcc 2.5.8. + +Peter + +-- + +re2c is distributed with no warranty whatever. The code is certain to +contain errors. Neither the author nor any contributor takes +responsibility for any consequences of its use. + +re2c is in the public domain. The data structures and algorithms used +in re2c are all either taken from documents available to the general +public or are inventions of the author. Programs generated by re2c may +be distributed freely. re2c itself may be distributed freely, in source +or binary, unchanged or modified. Distributors may charge whatever fees +they can obtain for re2c. + +If you do make use of re2c, or incorporate it into a larger project an +acknowledgement somewhere (documentation, research report, etc.) would +be appreciated. + +Please send bug reports and feedback (including suggestions for +improving the distribution) to + + peter@csg.uwaterloo.ca + +Include a small example and the banner from parser.y with bug reports. + diff --git a/actions.cc b/actions.cc new file mode 100644 index 00000000..0260b5fb --- /dev/null +++ b/actions.cc @@ -0,0 +1,505 @@ +#include +#include +#include +#include + +#include "globals.h" +#include "parser.h" +#include "dfa.h" + +Symbol *Symbol::first = NULL; + +Symbol::Symbol(const SubStr &str) : next(first), name(str), re(NULL) { + first = this; +} + +Symbol *Symbol::find(const SubStr &str){ + for(Symbol *sym = first; sym; sym = sym->next) + if(sym->name == str) return sym; + return new Symbol(str); +} + +void showIns(ostream &o, const Ins &i, const Ins &base){ + o.width(3); + o << &i - &base << ": "; + switch(i.i.tag){ + case CHAR: { + o << "match "; + for(const Ins *j = &(&i)[1]; j < (Ins*) i.i.link; ++j) + prtCh(o, j->c.value); + break; + } case GOTO: + o << "goto " << ((Ins*) i.i.link - &base); + break; + case FORK: + o << "fork " << ((Ins*) i.i.link - &base); + break; + case CTXT: + o << "term " << ((RuleOp*) i.i.link)->accept; + break; + case TERM: + o << "term " << ((RuleOp*) i.i.link)->accept; + break; + } + o << "\n"; +} + +uint RegExp::fixedLength(){ + return ~0; +} + +char *NullOp::type = "NullOp"; + +void NullOp::calcSize(Char*){ + size = 0; +} + +uint NullOp::fixedLength(){ + return 0; +} + +void NullOp::compile(Char*, Ins*){ + ; +} + +void NullOp::split(CharSet&){ + ; +} + +ostream& operator<<(ostream &o, const Range &r){ + if((r.ub - r.lb) == 1){ + prtCh(o, r.lb); + } else { + prtCh(o, r.lb); o << "-"; prtCh(o, r.ub-1); + } + return o << r.next; +} + +Range *doUnion(Range *r1, Range *r2){ + Range *r, **rP = &r; + for(;;){ + Range *s; + if(r1->lb <= r2->lb){ + s = new Range(*r1); + } else { + s = new Range(*r2); + } + *rP = s; + rP = &s->next; + for(;;){ + if(r1->lb <= r2->lb){ + if(r1->lb > s->ub) + break; + if(r1->ub > s->ub) + s->ub = r1->ub; + if(!(r1 = r1->next)){ + uint ub = 0; + for(; r2 && r2->lb <= s->ub; r2 = r2->next) + ub = r2->ub; + if(ub > s->ub) + s->ub = ub; + *rP = r2; + return r; + } + } else { + if(r2->lb > s->ub) + break; + if(r2->ub > s->ub) + s->ub = r2->ub; + if(!(r2 = r2->next)){ + uint ub = 0; + for(; r1 && r1->lb <= s->ub; r1 = r1->next) + ub = r1->ub; + if(ub > s->ub) + s->ub = ub; + *rP = r1; + return r; + } + } + } + } + *rP = NULL; + return r; +} + +Range *doDiff(Range *r1, Range *r2){ + Range *r, *s, **rP = &r; + for(; r1; r1 = r1->next){ + uint lb = r1->lb; + for(; r2 && r2->ub <= r1->lb; r2 = r2->next); + for(; r2 && r2->lb < r1->ub; r2 = r2->next){ + if(lb < r2->lb){ + *rP = s = new Range(lb, r2->lb); + rP = &s->next; + } + if((lb = r2->ub) >= r1->ub) + goto noMore; + } + *rP = s = new Range(lb, r1->ub); + rP = &s->next; + noMore:; + } + *rP = NULL; + return r; +} + +MatchOp *merge(MatchOp *m1, MatchOp *m2){ + if(!m1) + return m2; + if(!m2) + return m1; + return new MatchOp(doUnion(m1->match, m2->match)); +} + +char *MatchOp::type = "MatchOp"; + +void MatchOp::display(ostream &o) const{ + o << match; +} + +void MatchOp::calcSize(Char *rep){ + size = 1; + for(Range *r = match; r; r = r->next) + for(uint c = r->lb; c < r->ub; ++c) + if(rep[c] == c) + ++size; +} + +uint MatchOp::fixedLength(){ + return 1; +} + +void MatchOp::compile(Char *rep, Ins *i){ + i->i.tag = CHAR; + i->i.link = &i[size]; + Ins *j = &i[1]; + uint bump = size; + for(Range *r = match; r; r = r->next){ + for(uint c = r->lb; c < r->ub; ++c){ + if(rep[c] == c){ + j->c.value = c; + j->c.bump = --bump; + j++; + } + } + } +} + +void MatchOp::split(CharSet &s){ + for(Range *r = match; r; r = r->next){ + for(uint c = r->lb; c < r->ub; ++c){ + CharPtn *x = s.rep[c], *a = x->nxt; + if(!a){ + if(x->card == 1) + continue; + x->nxt = a = s.freeHead; + if(!(s.freeHead = s.freeHead->nxt)) + s.freeTail = &s.freeHead; + a->nxt = NULL; + x->fix = s.fix; + s.fix = x; + } + if(--(x->card) == 0){ + *s.freeTail = x; + *(s.freeTail = &x->nxt) = NULL; + } + s.rep[c] = a; + ++(a->card); + } + } + for(; s.fix; s.fix = s.fix->fix) + if(s.fix->card) + s.fix->nxt = NULL; +} + +RegExp *mkDiff(RegExp *e1, RegExp *e2){ + MatchOp *m1, *m2; + if(!(m1 = (MatchOp*) e1->isA(MatchOp::type))) + return NULL; + if(!(m2 = (MatchOp*) e2->isA(MatchOp::type))) + return NULL; + Range *r = doDiff(m1->match, m2->match); + return r? (RegExp*) new MatchOp(r) : (RegExp*) new NullOp; +} + +RegExp *doAlt(RegExp *e1, RegExp *e2){ + if(!e1) + return e2; + if(!e2) + return e1; + return new AltOp(e1, e2); +} + +RegExp *mkAlt(RegExp *e1, RegExp *e2){ + AltOp *a; + MatchOp *m1, *m2; + if((a = (AltOp*) e1->isA(AltOp::type))){ + if((m1 = (MatchOp*) a->exp1->isA(MatchOp::type))) + e1 = a->exp2; + } else if((m1 = (MatchOp*) e1->isA(MatchOp::type))){ + e1 = NULL; + } + if((a = (AltOp*) e2->isA(AltOp::type))){ + if((m2 = (MatchOp*) a->exp1->isA(MatchOp::type))) + e2 = a->exp2; + } else if((m2 = (MatchOp*) e2->isA(MatchOp::type))){ + e2 = NULL; + } + return doAlt(merge(m1, m2), doAlt(e1, e2)); +} + +char *AltOp::type = "AltOp"; + +void AltOp::calcSize(Char *rep){ + exp1->calcSize(rep); + exp2->calcSize(rep); + size = exp1->size + exp2->size + 2; +} + +uint AltOp::fixedLength(){ + uint l1 = exp1->fixedLength(); + uint l2 = exp1->fixedLength(); + if(l1 != l2 || l1 == ~0u) + return ~0; + return l1; +} + +void AltOp::compile(Char *rep, Ins *i){ + i->i.tag = FORK; + Ins *j = &i[exp1->size + 1]; + i->i.link = &j[1]; + exp1->compile(rep, &i[1]); + j->i.tag = GOTO; + j->i.link = &j[exp2->size + 1]; + exp2->compile(rep, &j[1]); +} + +void AltOp::split(CharSet &s){ + exp1->split(s); + exp2->split(s); +} + +char *CatOp::type = "CatOp"; + +void CatOp::calcSize(Char *rep){ + exp1->calcSize(rep); + exp2->calcSize(rep); + size = exp1->size + exp2->size; +} + +uint CatOp::fixedLength(){ + uint l1, l2; + if((l1 = exp1->fixedLength()) != ~0u ) + if((l2 = exp2->fixedLength()) != ~0u) + return l1+l2; + return ~0; +} + +void CatOp::compile(Char *rep, Ins *i){ + exp1->compile(rep, &i[0]); + exp2->compile(rep, &i[exp1->size]); +} + +void CatOp::split(CharSet &s){ + exp1->split(s); + exp2->split(s); +} + +char *CloseOp::type = "CloseOp"; + +void CloseOp::calcSize(Char *rep){ + exp->calcSize(rep); + size = exp->size + 1; +} + +void CloseOp::compile(Char *rep, Ins *i){ + exp->compile(rep, &i[0]); + i += exp->size; + i->i.tag = FORK; + i->i.link = i - exp->size; +} + +void CloseOp::split(CharSet &s){ + exp->split(s); +} + +RegExp *expr(Scanner &); + +uchar unescape(SubStr &s){ + s.len--; + uchar c; + if((c = *s.str++) != '\\' || s.len == 0) + return xlat[c]; + s.len--; + switch(c = *s.str++){ + case 'n': + return xlat['\n']; + case 't': + return xlat['\t']; + case 'v': + return xlat['\v']; + case 'b': + return xlat['\b']; + case 'r': + return xlat['\r']; + case 'f': + return xlat['\f']; + case 'a': + return xlat['\a']; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': { + uchar v = c - '0'; + for(; s.len != 0 && '0' <= (c = *s.str) && c <= '7'; s.len--, s.str++) + v = v*8 + (c - '0'); + return v; + } default: + return xlat[c]; + } +} + +Range *getRange(SubStr &s){ + uchar lb = unescape(s), ub; + if(s.len < 2 || *s.str != '-'){ + ub = lb; + } else { + s.len--; s.str++; + ub = unescape(s); + if(ub < lb){ + uchar tmp; + tmp = lb; lb = ub; ub = tmp; + } + } + return new Range(lb, ub+1); +} + +RegExp *matchChar(uint c){ + return new MatchOp(new Range(c, c+1)); +} + +RegExp *strToRE(SubStr s){ + s.len -= 2; s.str += 1; + if(s.len == 0) + return new NullOp; + RegExp *re = matchChar(unescape(s)); + while(s.len > 0) + re = new CatOp(re, matchChar(unescape(s))); + return re; +} + +RegExp *ranToRE(SubStr s){ + s.len -= 2; s.str += 1; + if(s.len == 0) + return new NullOp; + Range *r = getRange(s); + while(s.len > 0) + r = doUnion(r, getRange(s)); + return new MatchOp(r); +} + +char *RuleOp::type = "RuleOp"; + +RuleOp::RuleOp(RegExp *e, RegExp *c, Token *t, uint a) + : exp(e), ctx(c), ins(NULL), accept(a), code(t) { + ; +} + +void RuleOp::calcSize(Char *rep){ + exp->calcSize(rep); + ctx->calcSize(rep); + size = exp->size + ctx->size + 1; +} + +void RuleOp::compile(Char *rep, Ins *i){ + ins = i; + exp->compile(rep, &i[0]); + i += exp->size; + ctx->compile(rep, &i[0]); + i += ctx->size; + i->i.tag = TERM; + i->i.link = this; +} + +void RuleOp::split(CharSet &s){ + exp->split(s); + ctx->split(s); +} + +extern void printSpan(ostream&, uint, uint); + +void optimize(Ins *i){ + while(!isMarked(i)){ + mark(i); + if(i->i.tag == CHAR){ + i = (Ins*) i->i.link; + } else if(i->i.tag == GOTO || i->i.tag == FORK){ + Ins *target = (Ins*) i->i.link; + optimize(target); + if(target->i.tag == GOTO) + i->i.link = target->i.link == target? i : target; + if(i->i.tag == FORK){ + Ins *follow = (Ins*) &i[1]; + optimize(follow); + if(follow->i.tag == GOTO && follow->i.link == follow){ + i->i.tag = GOTO; + } else if(i->i.link == i){ + i->i.tag = GOTO; + i->i.link = follow; + } + } + return; + } else { + ++i; + } + } +} + +void genCode(ostream& o, RegExp *re){ + CharSet cs; + uint j; + memset(&cs, 0, sizeof(cs)); + for(j = 0; j < nChars; ++j){ + cs.rep[j] = &cs.ptn[0]; + cs.ptn[j].nxt = &cs.ptn[j+1]; + } + cs.freeHead = &cs.ptn[1]; + *(cs.freeTail = &cs.ptn[nChars-1].nxt) = NULL; + cs.ptn[0].card = nChars; + cs.ptn[0].nxt = NULL; + re->split(cs); +/* + for(uint k = 0; k < nChars;){ + for(j = k; ++k < nChars && cs.rep[k] == cs.rep[j];); + printSpan(cerr, j, k); + cerr << "\t" << cs.rep[j] - &cs.ptn[0] << endl; + } +*/ + Char rep[nChars]; + for(j = 0; j < nChars; ++j){ + if(!cs.rep[j]->nxt) + cs.rep[j]->nxt = &cs.ptn[j]; + rep[j] = (Char) (cs.rep[j]->nxt - &cs.ptn[0]); + } + + re->calcSize(rep); + Ins *ins = new Ins[re->size+1]; + memset(ins, 0, (re->size+1)*sizeof(Ins)); + re->compile(rep, ins); + Ins *eoi = &ins[re->size]; + eoi->i.tag = GOTO; + eoi->i.link = eoi; + + optimize(ins); + for(j = 0; j < re->size;){ + unmark(&ins[j]); + if(ins[j].i.tag == CHAR){ + j = (Ins*) ins[j].i.link - ins; + } else { + j++; + } + } + + DFA *dfa = new DFA(ins, re->size, 0, 256, rep); + dfa->emit(o); + delete dfa; + delete [] ins; +} diff --git a/basics.h b/basics.h new file mode 100644 index 00000000..2adaeb74 --- /dev/null +++ b/basics.h @@ -0,0 +1,9 @@ +#ifndef _basics_h +#define _basics_h + +typedef unsigned int uint; +typedef unsigned char uchar, byte; +typedef unsigned short ushort, word; +typedef unsigned long ulong, dword; + +#endif diff --git a/bootstrap/parser.cc b/bootstrap/parser.cc new file mode 100644 index 00000000..6d664005 --- /dev/null +++ b/bootstrap/parser.cc @@ -0,0 +1,531 @@ +#ifndef lint +static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; +#endif +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define yyclearin (yychar=(-1)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING (yyerrflag!=0) +#define YYPREFIX "yy" +#line 2 "parser.y" + +#include +#include +#include +#include +#include "globals.h" +#include "parser.h" +int yyparse(); +int yylex(); +void yyerror(char*); + +static uint accept; +static RegExp *spec; +static Scanner *in; + +#line 21 "parser.y" +typedef union { + Symbol *symbol; + RegExp *regexp; + Token *token; + char op; +} YYSTYPE; +#line 35 "y.tab.c" +#define CLOSE 257 +#define ID 258 +#define CODE 259 +#define RANGE 260 +#define STRING 261 +#define YYERRCODE 256 +short yylhs[] = { -1, + 0, 0, 0, 9, 2, 3, 3, 4, 4, 5, + 5, 6, 6, 7, 7, 1, 1, 8, 8, 8, + 8, +}; +short yylen[] = { 2, + 0, 2, 2, 4, 3, 0, 2, 1, 3, 1, + 3, 1, 2, 1, 2, 1, 2, 1, 1, 1, + 3, +}; +short yydefred[] = { 1, + 0, 0, 19, 20, 0, 2, 0, 0, 0, 12, + 0, 3, 0, 18, 0, 0, 0, 0, 0, 13, + 16, 0, 0, 21, 0, 0, 5, 0, 17, 4, +}; +short yydgoto[] = { 1, + 22, 6, 18, 7, 8, 9, 10, 11, 12, +}; +short yysindex[] = { 0, + -27, -49, 0, 0, -23, 0, -44, -84, -23, 0, + -243, 0, -23, 0, -39, -23, -23, -244, -23, 0, + 0, -239, -53, 0, -104, -84, 0, -23, 0, 0, +}; +short yyrindex[] = { 0, + 0, -31, 0, 0, 0, 0, -227, -17, -20, 0, + -40, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -36, 0, 0, -226, -16, 0, -19, 0, 0, +}; +short yygindex[] = { 0, + 0, 0, 0, 21, 18, 17, 1, 0, 0, +}; +#define YYTABLESIZE 243 +short yytable[] = { 14, + 14, 24, 16, 15, 15, 30, 14, 19, 18, 20, + 15, 13, 5, 21, 27, 18, 5, 29, 14, 17, + 10, 11, 15, 8, 9, 15, 10, 11, 20, 8, + 9, 6, 7, 23, 26, 28, 25, 0, 10, 11, + 0, 8, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 14, 0, 0, 0, 15, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 17, 10, 11, 0, 0, 0, 0, 0, 0, 17, + 0, 0, 0, 14, 17, 0, 0, 15, 0, 0, + 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 11, 0, 8, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, + 14, 15, 15, 15, 15, 18, 18, 18, 18, 18, + 2, 0, 3, 4, 14, 0, 3, 4, 10, 11, + 0, 8, 9, +}; +short yycheck[] = { 40, + 41, 41, 47, 40, 41, 59, 47, 92, 40, 9, + 47, 61, 40, 257, 259, 47, 40, 257, 59, 124, + 41, 41, 59, 41, 41, 5, 47, 47, 28, 47, + 47, 259, 259, 13, 17, 19, 16, -1, 59, 59, + -1, 59, 59, -1, -1, -1, -1, -1, -1, -1, + -1, 92, -1, -1, -1, 92, -1, -1, -1, -1, + 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 124, 92, 92, -1, -1, -1, -1, -1, -1, 124, + -1, -1, -1, 124, 124, -1, -1, 124, -1, -1, + -1, -1, 124, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 124, 124, -1, 124, 124, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 258, 259, 260, + 261, 258, 259, 260, 261, 257, 258, 259, 260, 261, + 258, -1, 260, 261, 258, -1, 260, 261, 259, 259, + -1, 259, 259, +}; +#define YYFINAL 1 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 261 +#if YYDEBUG +char *yyname[] = { +"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,"'('","')'",0,0,0,0,0,"'/'",0,0,0,0,0,0,0,0,0,0,0,"';'",0,"'='",0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'\\\\'",0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'|'",0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +"CLOSE","ID","CODE","RANGE","STRING", +}; +char *yyrule[] = { +"$accept : spec", +"spec :", +"spec : spec rule", +"spec : spec decl", +"decl : ID '=' expr ';'", +"rule : expr look CODE", +"look :", +"look : '/' expr", +"expr : diff", +"expr : expr '|' diff", +"diff : term", +"diff : diff '\\\\' term", +"term : factor", +"term : term factor", +"factor : primary", +"factor : primary close", +"close : CLOSE", +"close : close CLOSE", +"primary : ID", +"primary : RANGE", +"primary : STRING", +"primary : '(' expr ')'", +}; +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 500 +#define YYMAXDEPTH 500 +#endif +#endif +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short yyss[YYSTACKSIZE]; +YYSTYPE yyvs[YYSTACKSIZE]; +#define yystacksize YYSTACKSIZE +#line 121 "parser.y" + +void yyerror(char* s){ + in->fatal(s); +} + +int yylex(){ + return in->scan(); +} + +void parse(int i, ostream &o){ + char * fnamebuf; + char * token; + + o << "/* Generated by re2c 0.5 on "; + time_t now = time(&now); + o.write(ctime(&now), 24); + o << " */\n"; + + in = new Scanner(i); + + o << "#line " << in->line() << " \""; + if( fileName != NULL ) { + fnamebuf = strdup( fileName ); + } else { + fnamebuf = strdup( "" ); + } + token = strtok( fnamebuf, "\\" ); + for(;;) { + o << token; + token = strtok( NULL, "\\" ); + if( token == NULL ) break; + o << "\\\\"; + } + o << "\"\n"; + free( fnamebuf ); + + while(in->echo(o)){ + yyparse(); + if(spec) + genCode(o, spec); + o << "#line " << in->line() << "\n"; + } +} +#line 235 "y.tab.c" +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab +int +yyparse() +{ + register int yym, yyn, yystate; +#if YYDEBUG + register char *yys; + extern char *getenv(); + + if (yys = getenv("YYDEBUG")) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if (yyn = yydefred[yystate]) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#ifdef lint + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#ifdef lint + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { +case 1: +#line 40 "parser.y" +{ accept = 0; + spec = NULL; } +break; +case 2: +#line 43 "parser.y" +{ spec = spec? mkAlt(spec, yyvsp[0].regexp) : yyvsp[0].regexp; } +break; +case 4: +#line 48 "parser.y" +{ if(yyvsp[-3].symbol->re) + in->fatal("sym already defined"); + yyvsp[-3].symbol->re = yyvsp[-1].regexp; } +break; +case 5: +#line 54 "parser.y" +{ yyval.regexp = new RuleOp(yyvsp[-2].regexp, yyvsp[-1].regexp, yyvsp[0].token, accept++); } +break; +case 6: +#line 58 "parser.y" +{ yyval.regexp = new NullOp; } +break; +case 7: +#line 60 "parser.y" +{ yyval.regexp = yyvsp[0].regexp; } +break; +case 8: +#line 64 "parser.y" +{ yyval.regexp = yyvsp[0].regexp; } +break; +case 9: +#line 66 "parser.y" +{ yyval.regexp = mkAlt(yyvsp[-2].regexp, yyvsp[0].regexp); } +break; +case 10: +#line 70 "parser.y" +{ yyval.regexp = yyvsp[0].regexp; } +break; +case 11: +#line 72 "parser.y" +{ yyval.regexp = mkDiff(yyvsp[-2].regexp, yyvsp[0].regexp); + if(!yyval.regexp) + in->fatal("can only difference char sets"); + } +break; +case 12: +#line 79 "parser.y" +{ yyval.regexp = yyvsp[0].regexp; } +break; +case 13: +#line 81 "parser.y" +{ yyval.regexp = new CatOp(yyvsp[-1].regexp, yyvsp[0].regexp); } +break; +case 14: +#line 85 "parser.y" +{ yyval.regexp = yyvsp[0].regexp; } +break; +case 15: +#line 87 "parser.y" +{ + switch(yyvsp[0].op){ + case '*': + yyval.regexp = mkAlt(new CloseOp(yyvsp[-1].regexp), new NullOp()); + break; + case '+': + yyval.regexp = new CloseOp(yyvsp[-1].regexp); + break; + case '?': + yyval.regexp = mkAlt(yyvsp[-1].regexp, new NullOp()); + break; + } + } +break; +case 16: +#line 103 "parser.y" +{ yyval.op = yyvsp[0].op; } +break; +case 17: +#line 105 "parser.y" +{ yyval.op = (yyvsp[-1].op == yyvsp[0].op) ? yyvsp[-1].op : '*'; } +break; +case 18: +#line 109 "parser.y" +{ if(!yyvsp[0].symbol->re) + in->fatal("can't find symbol"); + yyval.regexp = yyvsp[0].symbol->re; } +break; +case 19: +#line 113 "parser.y" +{ yyval.regexp = yyvsp[0].regexp; } +break; +case 20: +#line 115 "parser.y" +{ yyval.regexp = yyvsp[0].regexp; } +break; +case 21: +#line 117 "parser.y" +{ yyval.regexp = yyvsp[-1].regexp; } +break; +#line 476 "y.tab.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} diff --git a/bootstrap/re2c.man b/bootstrap/re2c.man new file mode 100644 index 00000000..b74aaafb --- /dev/null +++ b/bootstrap/re2c.man @@ -0,0 +1,660 @@ + + + +RE2C(1) RE2C(1) + + +NNAAMMEE + re2c - convert regular expressions to C/C++ + + +SSYYNNOOPPSSIISS + rree22cc [--eessbb] _n_a_m_e + + +DDEESSCCRRIIPPTTIIOONN + rree22cc is a preprocessor that generates C-based recognizers + from regular expressions. The input to rree22cc consists of + C/C++ source interleaved with comments of the form //**!!rree22cc + ... **// which contain scanner specifications. In the out- + put these comments are replaced with code that, when exe- + cuted, will find the next input token and then execute + some user-supplied token-specific code. + + For example, given the following code + + #define NULL ((char*) 0) + char *scan(char *p){ + char *q; + #define YYCTYPE char + #define YYCURSOR p + #define YYLIMIT p + #define YYMARKER q + #define YYFILL(n) + /*!re2c + [0-9]+ {return YYCURSOR;} + [\000-\377] {return NULL;} + */ + } + + rree22cc will generate + + /* Generated by re2c on Sat Apr 16 11:40:58 1994 */ + #line 1 "simple.re" + #define NULL ((char*) 0) + char *scan(char *p){ + char *q; + #define YYCTYPE char + #define YYCURSOR p + #define YYLIMIT p + #define YYMARKER q + #define YYFILL(n) + { + YYCTYPE yych; + unsigned int yyaccept; + goto yy0; + yy1: ++YYCURSOR; + yy0: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= '/') goto yy4; + + + +Version 0.5 8 April 1994 1 + + + + + +RE2C(1) RE2C(1) + + + if(yych >= ':') goto yy4; + yy2: yych = *++YYCURSOR; + goto yy7; + yy3: + #line 10 + {return YYCURSOR;} + yy4: yych = *++YYCURSOR; + yy5: + #line 11 + {return NULL;} + yy6: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + yy7: if(yych <= '/') goto yy3; + if(yych <= '9') goto yy6; + goto yy3; + } + #line 12 + + } + + +OOPPTTIIOONNSS + rree22cc provides the following options: + + --ee Cross-compile from an ASCII platform to an EBCDIC + one. + + --ss Generate nested iiffs for some sswwiittcchhes. Many com- + pilers need this assist to generate better code. + + --bb Implies --ss. Use bit vectors as well in the attempt + to coax better code out of the compiler. Most use- + ful for specifications with more than a few key- + words (e.g. for most programming languages). + + +IINNTTEERRFFAACCEE CCOODDEE + Unlike other scanner generators, rree22cc does not generate + complete scanners: the user must supply some interface + code. In particular, the user must define the following + macros: + + YYYYCCHHAARR Type used to hold an input symbol. Usually cchhaarr or + uunnssiiggnneedd cchhaarr. + + YYYYCCUURRSSOORR + _l-expression of type **YYYYCCHHAARR that points to the + current input symbol. The generated code advances + YYYYCCUURRSSOORR as symbols are matched. On entry, YYYYCCUURR-- + SSOORR is assumed to point to the first character of + the current token. On exit, YYYYCCUURRSSOORR will point to + the first character of the following token. + + + + +Version 0.5 8 April 1994 2 + + + + + +RE2C(1) RE2C(1) + + + YYLLIIMMIITT Expression of type **YYYYCCHHAARR that marks the end of + the buffer (YYLLIIMMIITT[[--11]] is the last character in the + buffer). The generated code repeatedly compares + YYYYCCUURRSSOORR to YYLLIIMMIITT to determine when the buffer + needs (re)filling. + + YYYYMMAARRKKEERR + _l-expression of type **YYYYCCHHAARR. The generated code + saves backtracking information in YYYYMMAARRKKEERR. + + YYYYFFIILLLL((_n)) + The generated code "calls" YYYYFFIILLLL when the buffer + needs (re)filling: at least _n additional charac- + ters should be provided. YYYYFFIILLLL should adjust + YYYYCCUURRSSOORR, YYYYLLIIMMIITT and YYYYMMAARRKKEERR as needed. Note + that for typical programming languages _n will be + the length of the longest keyword plus one. + + +SSCCAANNNNEERR SSPPEECCIIFFIICCAATTIIOONNSS + Each scanner specification consists of a set of _r_u_l_e_s and + name definitions. Rules consist of a regular expression + along with a block of C/C++ code that is to be executed + when the associated regular expression is matched. Name + definitions are of the form ``_n_a_m_e == _r_e_g_u_l_a_r _e_x_p_r_e_s_- + _s_i_o_n;;''. + + +SSUUMMMMAARRYY OOFF RREE22CC RREEGGUULLAARR EEXXPPRREESSSSIIOONNSS + ""ffoooo"" the literal string ffoooo. ANSI-C escape sequences + can be used. + + [[xxyyzz]] a "character class"; in this case, the regular + expression matches either an 'xx', a 'yy', or a 'zz'. + + [[aabbjj--ooZZ]] + a "character class" with a range in it; matches an + 'aa', a 'bb', any letter from 'jj' through 'oo', or a + 'ZZ'. + + _r\\_s match any _r which isn't an _s. _r and _s must be regu- + lar expressions which can be expressed as character + classes. + + _r** zero or more _r's, where _r is any regular expression + + _r++ one or more _r's + + _r?? zero or one _r's (that is, "an optional _r") + + name the expansion of the "name" definition (see above) + + ((_r)) an _r; parentheses are used to override precedence + (see below) + + + +Version 0.5 8 April 1994 3 + + + + + +RE2C(1) RE2C(1) + + + _r_s an _r followed by an _s ("concatenation") + + _r||_s either an _r or an _s + + _r//_s an _r but only if it is followed by an _s. The s is + not part of the matched text. This type of regular + expression is called "trailing context". + + The regular expressions listed above are grouped according + to precedence, from highest precedence at the top to low- + est at the bottom. Those grouped together have equal + precedence. + + +AA LLAARRGGEERR EEXXAAMMPPLLEE + #include + #include + #include + #include + + #define ADDEQ 257 + #define ANDAND 258 + #define ANDEQ 259 + #define ARRAY 260 + #define ASM 261 + #define AUTO 262 + #define BREAK 263 + #define CASE 264 + #define CHAR 265 + #define CONST 266 + #define CONTINUE 267 + #define DECR 268 + #define DEFAULT 269 + #define DEREF 270 + #define DIVEQ 271 + #define DO 272 + #define DOUBLE 273 + #define ELLIPSIS 274 + #define ELSE 275 + #define ENUM 276 + #define EQL 277 + #define EXTERN 278 + #define FCON 279 + #define FLOAT 280 + #define FOR 281 + #define FUNCTION 282 + #define GEQ 283 + #define GOTO 284 + #define ICON 285 + #define ID 286 + #define IF 287 + #define INCR 288 + #define INT 289 + #define LEQ 290 + + + +Version 0.5 8 April 1994 4 + + + + + +RE2C(1) RE2C(1) + + + #define LONG 291 + #define LSHIFT 292 + #define LSHIFTEQ 293 + #define MODEQ 294 + #define MULEQ 295 + #define NEQ 296 + #define OREQ 297 + #define OROR 298 + #define POINTER 299 + #define REGISTER 300 + #define RETURN 301 + #define RSHIFT 302 + #define RSHIFTEQ 303 + #define SCON 304 + #define SHORT 305 + #define SIGNED 306 + #define SIZEOF 307 + #define STATIC 308 + #define STRUCT 309 + #define SUBEQ 310 + #define SWITCH 311 + #define TYPEDEF 312 + #define UNION 313 + #define UNSIGNED 314 + #define VOID 315 + #define VOLATILE 316 + #define WHILE 317 + #define XOREQ 318 + #define EOI 319 + + typedef unsigned int uint; + typedef unsigned char uchar; + + #define BSIZE 8192 + + #define YYCTYPE uchar + #define YYCURSOR cursor + #define YYLIMIT s->lim + #define YYMARKER s->ptr + #define YYFILL(n) {cursor = fill(s, cursor);} + + #define RET(i) {s->cur = cursor; return i;} + + typedef struct Scanner { + int fd; + uchar *bot, *tok, *ptr, *cur, *pos, *lim, *top, *eof; + uint line; + } Scanner; + + uchar *fill(Scanner *s, uchar *cursor){ + if(!s->eof){ + uint cnt = s->tok - s->bot; + if(cnt){ + memcpy(s->bot, s->tok, s->lim - s->tok); + + + +Version 0.5 8 April 1994 5 + + + + + +RE2C(1) RE2C(1) + + + s->tok = s->bot; + s->ptr -= cnt; + cursor -= cnt; + s->pos -= cnt; + s->lim -= cnt; + } + if((s->top - s->lim) < BSIZE){ + uchar *buf = (uchar*) + malloc(((s->lim - s->bot) + BSIZE)*sizeof(uchar)); + memcpy(buf, s->tok, s->lim - s->tok); + s->tok = buf; + s->ptr = &buf[s->ptr - s->bot]; + cursor = &buf[cursor - s->bot]; + s->pos = &buf[s->pos - s->bot]; + s->lim = &buf[s->lim - s->bot]; + s->top = &s->lim[BSIZE]; + free(s->bot); + s->bot = buf; + } + if((cnt = read(s->fd, (char*) s->lim, BSIZE)) != BSIZE){ + s->eof = &s->lim[cnt]; *(s->eof)++ = '\n'; + } + s->lim += cnt; + } + return cursor; + } + + int scan(Scanner *s){ + uchar *cursor = s->cur; + std: + s->tok = cursor; + /*!re2c + any = [\000-\377]; + O = [0-7]; + D = [0-9]; + L = [a-zA-Z_]; + H = [a-fA-F0-9]; + E = [Ee] [+-]? D+; + FS = [fFlL]; + IS = [uUlL]*; + ESC = [\\] ([abfnrtv?'"\\] | "x" H+ | O+); + */ + + /*!re2c + "/*" { goto comment; } + + "auto" { RET(AUTO); } + "break" { RET(BREAK); } + "case" { RET(CASE); } + "char" { RET(CHAR); } + "const" { RET(CONST); } + "continue" { RET(CONTINUE); } + "default" { RET(DEFAULT); } + "do" { RET(DO); } + + + +Version 0.5 8 April 1994 6 + + + + + +RE2C(1) RE2C(1) + + + "double" { RET(DOUBLE); } + "else" { RET(ELSE); } + "enum" { RET(ENUM); } + "extern" { RET(EXTERN); } + "float" { RET(FLOAT); } + "for" { RET(FOR); } + "goto" { RET(GOTO); } + "if" { RET(IF); } + "int" { RET(INT); } + "long" { RET(LONG); } + "register" { RET(REGISTER); } + "return" { RET(RETURN); } + "short" { RET(SHORT); } + "signed" { RET(SIGNED); } + "sizeof" { RET(SIZEOF); } + "static" { RET(STATIC); } + "struct" { RET(STRUCT); } + "switch" { RET(SWITCH); } + "typedef" { RET(TYPEDEF); } + "union" { RET(UNION); } + "unsigned" { RET(UNSIGNED); } + "void" { RET(VOID); } + "volatile" { RET(VOLATILE); } + "while" { RET(WHILE); } + + L (L|D)* { RET(ID); } + + ("0" [xX] H+ IS?) | ("0" D+ IS?) | (D+ IS?) | + (['] (ESC|any\[\n\\'])* [']) + { RET(ICON); } + + (D+ E FS?) | (D* "." D+ E? FS?) | (D+ "." D* E? FS?) + { RET(FCON); } + + (["] (ESC|any\[\n\\"])* ["]) + { RET(SCON); } + + "..." { RET(ELLIPSIS); } + ">>=" { RET(RSHIFTEQ); } + "<<=" { RET(LSHIFTEQ); } + "+=" { RET(ADDEQ); } + "-=" { RET(SUBEQ); } + "*=" { RET(MULEQ); } + "/=" { RET(DIVEQ); } + "%=" { RET(MODEQ); } + "&=" { RET(ANDEQ); } + "^=" { RET(XOREQ); } + "|=" { RET(OREQ); } + ">>" { RET(RSHIFT); } + "<<" { RET(LSHIFT); } + "++" { RET(INCR); } + "--" { RET(DECR); } + "->" { RET(DEREF); } + "&&" { RET(ANDAND); } + + + +Version 0.5 8 April 1994 7 + + + + + +RE2C(1) RE2C(1) + + + "||" { RET(OROR); } + "<=" { RET(LEQ); } + ">=" { RET(GEQ); } + "==" { RET(EQL); } + "!=" { RET(NEQ); } + ";" { RET(';'); } + "{" { RET('{'); } + "}" { RET('}'); } + "," { RET(','); } + ":" { RET(':'); } + "=" { RET('='); } + "(" { RET('('); } + ")" { RET(')'); } + "[" { RET('['); } + "]" { RET(']'); } + "." { RET('.'); } + "&" { RET('&'); } + "!" { RET('!'); } + "~" { RET('~'); } + "-" { RET('-'); } + "+" { RET('+'); } + "*" { RET('*'); } + "/" { RET('/'); } + "%" { RET('%'); } + "<" { RET('<'); } + ">" { RET('>'); } + "^" { RET('^'); } + "|" { RET('|'); } + "?" { RET('?'); } + + + [ \t\v\f]+ { goto std; } + + "\n" + { + if(cursor == s->eof) RET(EOI); + s->pos = cursor; s->line++; + goto std; + } + + any + { + printf("unexpected character: %c\n", *s->tok); + goto std; + } + */ + + comment: + /*!re2c + "*/" { goto std; } + "\n" + { + if(cursor == s->eof) RET(EOI); + s->tok = s->pos = cursor; s->line++; + + + +Version 0.5 8 April 1994 8 + + + + + +RE2C(1) RE2C(1) + + + goto comment; + } + any { goto comment; } + */ + } + + main(){ + Scanner in; + int t; + memset((char*) &in, 0, sizeof(in)); + in.fd = 0; + while((t = scan(&in)) != EOI){ + /* + printf("%d\t%.*s\n", t, in.cur - in.tok, in.tok); + printf("%d\n", t); + */ + } + close(in.fd); + } + + +SSEEEE AALLSSOO + flex(1), lex(1). + + +FFEEAATTUURREESS + rree22cc does not provide a default action: the generated code + assumes that the input will consist of a sequence of + tokens. Typically this can be dealt with by adding a rule + such as the one for unexpected characters in the example + above. + + The user must arrange for a sentinel token to appear at + the end of input (and provide a rule for matching it): + rree22cc does not provide an <<<>>> expression. If the + source is from a null-byte terminated string, a rule + matching a null character will suffice. If the source is + from a file then the approach taken in the example can be + used: pad the input with a newline (or some other charac- + ter that can't appear within another token); upon recog- + nizing such a character check to see if it is the sentinel + and act accordingly. + + rree22cc does not provide start conditions: use a separate + scanner specification for each start condition (as illus- + trated in the above example). + + No [^x]. Use difference instead. + +BBUUGGSS + Only fixed length trailing context can be handled. + + The maximum value appearing as a parameter _n to YYYYFFIILLLL is + not provided to the generated code (this value is needed + + + +Version 0.5 8 April 1994 9 + + + + + +RE2C(1) RE2C(1) + + + for constructing the interface code). Note that this + value is usually relatively small: for typical programming + languages _n will be the length of the longest keyword plus + one. + + Difference only works for character sets. + + The rree22cc internal algorithms need documentation. + + +AAUUTTHHOORR + Please send bug reports, fixes and feedback to: + + Peter Bumbulis + Computer Systems Group + University of Waterloo + Waterloo, Ontario + N2L 3G1 + Internet: peter@csg.uwaterloo.ca + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Version 0.5 8 April 1994 10 + + diff --git a/bootstrap/scanner.cc b/bootstrap/scanner.cc new file mode 100644 index 00000000..19b42597 --- /dev/null +++ b/bootstrap/scanner.cc @@ -0,0 +1,470 @@ +/* Generated by re2c 0.5 on Sat May 15 11:35:52 1999 */ +#line 1 "scanner.re" +#include +#include +#include +#include +#include "scanner.h" +#include "parser.h" +#include "y.tab.h" + +extern YYSTYPE yylval; + +#define BSIZE 8192 + +#define YYCTYPE uchar +#define YYCURSOR cursor +#define YYLIMIT lim +#define YYMARKER ptr +#define YYFILL(n) {cursor = fill(cursor);} + +#define RETURN(i) {cur = cursor; return i;} + + +Scanner::Scanner(int i) : in(i), + bot(NULL), tok(NULL), ptr(NULL), cur(NULL), pos(NULL), lim(NULL), + top(NULL), eof(NULL), tchar(0), tline(0), cline(1) { + ; +} + +uchar *Scanner::fill(uchar *cursor){ + if(!eof){ + uint cnt = tok - bot; + if(cnt){ + memcpy(bot, tok, lim - tok); + tok = bot; + ptr -= cnt; + cursor -= cnt; + pos -= cnt; + lim -= cnt; + } + if((top - lim) < BSIZE){ + uchar *buf = new uchar[(lim - bot) + BSIZE]; + memcpy(buf, tok, lim - tok); + tok = buf; + ptr = &buf[ptr - bot]; + cursor = &buf[cursor - bot]; + pos = &buf[pos - bot]; + lim = &buf[lim - bot]; + top = &lim[BSIZE]; + delete [] bot; + bot = buf; + } + if((cnt = read(in, (char*) lim, BSIZE)) != BSIZE){ + eof = &lim[cnt]; *eof++ = '\n'; + } + lim += cnt; + } + return cursor; +} + +#line 68 + + +int Scanner::echo(ostream &out){ + uchar *cursor = cur; + tok = cursor; +echo: +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy0; +yy1: ++YYCURSOR; +yy0: + if((YYLIMIT - YYCURSOR) < 7) YYFILL(7); + yych = *YYCURSOR; + if(yych == '\n') goto yy4; + if(yych != '/') goto yy6; +yy2: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == '*') goto yy7; +yy3: +#line 82 + { goto echo; } +yy4: yych = *++YYCURSOR; +yy5: +#line 78 + { if(cursor == eof) RETURN(0); + out.write(tok, cursor - tok); + tok = pos = cursor; cline++; + goto echo; } +yy6: yych = *++YYCURSOR; + goto yy3; +yy7: yych = *++YYCURSOR; + if(yych == '!') goto yy9; +yy8: YYCURSOR = YYMARKER; + switch(yyaccept){ + case 0: goto yy3; + } +yy9: yych = *++YYCURSOR; + if(yych != 'r') goto yy8; +yy10: yych = *++YYCURSOR; + if(yych != 'e') goto yy8; +yy11: yych = *++YYCURSOR; + if(yych != '2') goto yy8; +yy12: yych = *++YYCURSOR; + if(yych != 'c') goto yy8; +yy13: yych = *++YYCURSOR; +yy14: +#line 75 + { out.write(tok, &cursor[-7] - tok); + tok = cursor; + RETURN(1); } +} +#line 83 + +} + + +int Scanner::scan(){ + uchar *cursor = cur; + uint depth; + +scan: + tchar = cursor - pos; + tline = cline; + tok = cursor; +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy15; +yy16: ++YYCURSOR; +yy15: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= ':'){ + if(yych <= '"'){ + if(yych <= '\n'){ + if(yych <= '\b') goto yy35; + if(yych <= '\t') goto yy31; + goto yy33; + } else { + if(yych == ' ') goto yy31; + if(yych <= '!') goto yy35; + goto yy23; + } + } else { + if(yych <= '*'){ + if(yych <= '\'') goto yy35; + if(yych <= ')') goto yy27; + goto yy21; + } else { + if(yych <= '+') goto yy28; + if(yych == '/') goto yy19; + goto yy35; + } + } + } else { + if(yych <= 'Z'){ + if(yych <= '='){ + if(yych == '<') goto yy35; + goto yy27; + } else { + if(yych == '?') goto yy28; + if(yych <= '@') goto yy35; + goto yy29; + } + } else { + if(yych <= '`'){ + if(yych <= '[') goto yy25; + if(yych <= '\\') goto yy27; + goto yy35; + } else { + if(yych <= 'z') goto yy29; + if(yych <= '{') goto yy17; + if(yych <= '|') goto yy27; + goto yy35; + } + } + } +yy17: yych = *++YYCURSOR; +yy18: +#line 96 + { depth = 1; + goto code; + } +yy19: yych = *++YYCURSOR; + if(yych == '*') goto yy54; +yy20: +#line 115 + { RETURN(*tok); } +yy21: yych = *++YYCURSOR; + if(yych == '/') goto yy52; +yy22: +#line 117 + { yylval.op = *tok; + RETURN(CLOSE); } +yy23: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != '\n') goto yy48; +yy24: +#line 108 + { fatal("bad string"); } +yy25: yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != '\n') goto yy42; +yy26: +#line 113 + { fatal("bad character constant"); } +yy27: yych = *++YYCURSOR; + goto yy20; +yy28: yych = *++YYCURSOR; + goto yy22; +yy29: yych = *++YYCURSOR; + goto yy40; +yy30: +#line 120 + { cur = cursor; + yylval.symbol = Symbol::find(token()); + return ID; } +yy31: yych = *++YYCURSOR; + goto yy38; +yy32: +#line 124 + { goto scan; } +yy33: yych = *++YYCURSOR; +yy34: +#line 126 + { if(cursor == eof) RETURN(0); + pos = cursor; cline++; + goto scan; + } +yy35: yych = *++YYCURSOR; +yy36: +#line 131 + { cerr << "unexpected character: " << *tok << endl; + goto scan; + } +yy37: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy38: if(yych == '\t') goto yy37; + if(yych == ' ') goto yy37; + goto yy32; +yy39: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy40: if(yych <= '@'){ + if(yych <= '/') goto yy30; + if(yych <= '9') goto yy39; + goto yy30; + } else { + if(yych <= 'Z') goto yy39; + if(yych <= '`') goto yy30; + if(yych <= 'z') goto yy39; + goto yy30; + } +yy41: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy42: if(yych <= '['){ + if(yych != '\n') goto yy41; + } else { + if(yych <= '\\') goto yy44; + if(yych <= ']') goto yy45; + goto yy41; + } +yy43: YYCURSOR = YYMARKER; + switch(yyaccept){ + case 0: goto yy24; + case 1: goto yy26; + } +yy44: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych == '\n') goto yy43; + goto yy41; +yy45: yych = *++YYCURSOR; +yy46: +#line 110 + { cur = cursor; + yylval.regexp = ranToRE(token()); + return RANGE; } +yy47: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy48: if(yych <= '!'){ + if(yych == '\n') goto yy43; + goto yy47; + } else { + if(yych <= '"') goto yy50; + if(yych != '\\') goto yy47; + } +yy49: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych == '\n') goto yy43; + goto yy47; +yy50: yych = *++YYCURSOR; +yy51: +#line 105 + { cur = cursor; + yylval.regexp = strToRE(token()); + return STRING; } +yy52: yych = *++YYCURSOR; +yy53: +#line 102 + { tok = cursor; + RETURN(0); } +yy54: yych = *++YYCURSOR; +yy55: +#line 99 + { depth = 1; + goto comment; } +} +#line 134 + + +code: +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy56; +yy57: ++YYCURSOR; +yy56: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych <= '\t') goto yy64; + goto yy62; + } else { + if(yych == '"') goto yy66; + goto yy64; + } + } else { + if(yych <= '{'){ + if(yych <= '\'') goto yy67; + if(yych <= 'z') goto yy64; + goto yy60; + } else { + if(yych != '}') goto yy64; + } + } +yy58: yych = *++YYCURSOR; +yy59: +#line 138 + { if(--depth == 0){ + cur = cursor; + yylval.token = new Token(token(), tline); + return CODE; + } + goto code; } +yy60: yych = *++YYCURSOR; +yy61: +#line 144 + { ++depth; + goto code; } +yy62: yych = *++YYCURSOR; +yy63: +#line 146 + { if(cursor == eof) fatal("missing '}'"); + pos = cursor; cline++; + goto code; + } +yy64: yych = *++YYCURSOR; +yy65: +#line 150 + { goto code; } +yy66: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == '\n') goto yy65; + goto yy73; +yy67: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == '\n') goto yy65; + goto yy69; +yy68: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy69: if(yych <= '&'){ + if(yych != '\n') goto yy68; + } else { + if(yych <= '\'') goto yy64; + if(yych == '\\') goto yy71; + goto yy68; + } +yy70: YYCURSOR = YYMARKER; + switch(yyaccept){ + case 0: goto yy65; + } +yy71: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych == '\n') goto yy70; + goto yy68; +yy72: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy73: if(yych <= '!'){ + if(yych == '\n') goto yy70; + goto yy72; + } else { + if(yych <= '"') goto yy64; + if(yych != '\\') goto yy72; + } +yy74: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych == '\n') goto yy70; + goto yy72; +} +#line 151 + + +comment: +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy75; +yy76: ++YYCURSOR; +yy75: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= ')'){ + if(yych == '\n') goto yy80; + goto yy82; + } else { + if(yych <= '*') goto yy77; + if(yych == '/') goto yy79; + goto yy82; + } +yy77: yych = *++YYCURSOR; + if(yych == '/') goto yy85; +yy78: +#line 165 + { goto comment; } +yy79: yych = *++YYCURSOR; + if(yych == '*') goto yy83; + goto yy78; +yy80: yych = *++YYCURSOR; +yy81: +#line 161 + { if(cursor == eof) RETURN(0); + tok = pos = cursor; cline++; + goto comment; + } +yy82: yych = *++YYCURSOR; + goto yy78; +yy83: yych = *++YYCURSOR; +yy84: +#line 159 + { ++depth; + goto comment; } +yy85: yych = *++YYCURSOR; +yy86: +#line 155 + { if(--depth == 0) + goto scan; + else + goto comment; } +} +#line 166 + +} + +void Scanner::fatal(char *msg){ + cerr << "line " << tline << ", column " << (tchar + 1) << ": " + << msg << endl; + exit(1); +} diff --git a/bootstrap/y.tab.h b/bootstrap/y.tab.h new file mode 100644 index 00000000..d7b3702d --- /dev/null +++ b/bootstrap/y.tab.h @@ -0,0 +1,12 @@ +#define CLOSE 257 +#define ID 258 +#define CODE 259 +#define RANGE 260 +#define STRING 261 +typedef union { + Symbol *symbol; + RegExp *regexp; + Token *token; + char op; +} YYSTYPE; +extern YYSTYPE yylval; diff --git a/code.cc b/code.cc new file mode 100644 index 00000000..8aaf6a88 --- /dev/null +++ b/code.cc @@ -0,0 +1,665 @@ +#include +#include +#include +#include +#include "substr.h" +#include "globals.h" +#include "dfa.h" + +// there must be at least one span in list; all spans must cover +// same range + +void Go::compact(){ + // arrange so that adjacent spans have different targets + uint i = 0; + for(uint j = 1; j < nSpans; ++j){ + if(span[j].to != span[i].to){ + ++i; span[i].to = span[j].to; + } + span[i].ub = span[j].ub; + } + nSpans = i + 1; +} + +void Go::unmap(Go *base, State *x){ + Span *s = span, *b = base->span, *e = &b[base->nSpans]; + uint lb = 0; + s->ub = 0; + s->to = NULL; + for(; b != e; ++b){ + if(b->to == x){ + if((s->ub - lb) > 1) + s->ub = b->ub; + } else { + if(b->to != s->to){ + if(s->ub){ + lb = s->ub; ++s; + } + s->to = b->to; + } + s->ub = b->ub; + } + } + s->ub = e[-1].ub; ++s; + nSpans = s - span; +} + +void doGen(Go *g, State *s, uchar *bm, uchar m){ +Span *b = g->span, *e = &b[g->nSpans]; +uint lb = 0; +for(; b < e; ++b){ + if(b->to == s) + for(; lb < b->ub; ++lb) bm[lb] |= m; + lb = b->ub; +} +} + +void prt(ostream& o, Go *g, State *s){ +Span *b = g->span, *e = &b[g->nSpans]; +uint lb = 0; +for(; b < e; ++b){ + if(b->to == s) + printSpan(o, lb, b->ub); + lb = b->ub; +} +} + +bool matches(Go *g1, State *s1, Go *g2, State *s2){ +Span *b1 = g1->span, *e1 = &b1[g1->nSpans]; +uint lb1 = 0; +Span *b2 = g2->span, *e2 = &b2[g2->nSpans]; +uint lb2 = 0; +for(;;){ + for(; b1 < e1 && b1->to != s1; ++b1) lb1 = b1->ub; + for(; b2 < e2 && b2->to != s2; ++b2) lb2 = b2->ub; + if(b1 == e1) return b2 == e2; + if(b2 == e2) return false; + if(lb1 != lb2 || b1->ub != b2->ub) return false; + ++b1; ++b2; +} +} + +class BitMap { +public: +static BitMap *first; +Go *go; +State *on; +BitMap *next; +uint i; +uchar m; +public: +static BitMap *find(Go*, State*); +static BitMap *find(State*); +static void gen(ostream&, uint, uint); +static void stats(); +BitMap(Go*, State*); +}; + +BitMap *BitMap::first = NULL; + +BitMap::BitMap(Go *g, State *x) : go(g), on(x), next(first) { +first = this; +} + +BitMap *BitMap::find(Go *g, State *x){ +for(BitMap *b = first; b; b = b->next){ + if(matches(b->go, b->on, g, x)) + return b; + } + return new BitMap(g, x); +} + +BitMap *BitMap::find(State *x){ + for(BitMap *b = first; b; b = b->next){ + if(b->on == x) + return b; + } + return NULL; +} + +void BitMap::gen(ostream &o, uint lb, uint ub){ + BitMap *b = first; + if(b){ + o << "\tstatic unsigned char yybm[] = {"; + uint n = ub - lb; + uchar *bm = new uchar[n]; + memset(bm, 0, n); + for(uint i = 0; b; i += n){ + for(uchar m = 0x80; b && m; b = b->next, m >>= 1){ + b->i = i; b->m = m; + doGen(b->go, b->on, bm-lb, m); + } + for(uint j = 0; j < n; ++j){ + if(j%8 == 0) o << "\n\t"; + o << setw(3) << (uint) bm[j] << ", "; + } + } + o << "\n\t};\n"; + } +} + +void BitMap::stats(){ + uint n = 0; + for(BitMap *b = first; b; b = b->next){ +prt(cerr, b->go, b->on); cerr << endl; + ++n; + } + cerr << n << " bitmaps\n"; + first = NULL; +} + +void genGoTo(ostream &o, State *to){ + o << "\tgoto yy" << to->label << ";\n"; +} + +void genIf(ostream &o, char *cmp, uint v){ + o << "\tif(yych " << cmp << " '"; + prtCh(o, v); + o << "')"; +} + +void indent(ostream &o, uint i){ + while(i-- > 0) + o << "\t"; +} + +static void need(ostream &o, uint n){ + if(n == 1) + o << "\tif(YYLIMIT == YYCURSOR) YYFILL(1);\n"; + else + o << "\tif((YYLIMIT - YYCURSOR) < " << n << ") YYFILL(" << n << ");\n"; + o << "\tyych = *YYCURSOR;\n"; +} + +void Match::emit(ostream &o){ + if(state->link){ + o << "\t++YYCURSOR;\n"; + need(o, state->depth); + } else { + o << "\tyych = *++YYCURSOR;\n"; + } +} + +void Enter::emit(ostream &o){ + if(state->link){ + o << "\t++YYCURSOR;\n"; + o << "yy" << label << ":\n"; + need(o, state->depth); + } else { + o << "\tyych = *++YYCURSOR;\n"; + o << "yy" << label << ":\n"; + } +} + +void Save::emit(ostream &o){ + o << "\tyyaccept = " << selector << ";\n"; + if(state->link){ + o << "\tYYMARKER = ++YYCURSOR;\n"; + need(o, state->depth); + } else { + o << "\tyych = *(YYMARKER = ++YYCURSOR);\n"; + } +} + +Move::Move(State *s) : Action(s) { + ; +} + +void Move::emit(ostream &o){ + ; +} + +Accept::Accept(State *x, uint n, uint *s, State **r) + : Action(x), nRules(n), saves(s), rules(r){ + ; +} + +void Accept::emit(ostream &o){ + bool first = true; + for(uint i = 0; i < nRules; ++i) + if(saves[i] != ~0u){ + if(first){ + first = false; + o << "\tYYCURSOR = YYMARKER;\n"; + o << "\tswitch(yyaccept){\n"; + } + o << "\tcase " << saves[i] << ":"; + genGoTo(o, rules[i]); + } + if(!first) + o << "\t}\n"; +} + +Rule::Rule(State *s, RuleOp *r) : Action(s), rule(r) { + ; +} + +void Rule::emit(ostream &o){ + uint back = rule->ctx->fixedLength(); + if(back != ~0u && back > 0u) + o << "\tYYCURSOR -= " << back << ";"; + o << "\n#line " << rule->code->line + << "\n\t" << rule->code->text << "\n"; +} + +void doLinear(ostream &o, uint i, Span *s, uint n, State *next){ + for(;;){ + State *bg = s[0].to; + while(n >= 3 && s[2].to == bg && (s[1].ub - s[0].ub) == 1){ + if(s[1].to == next && n == 3){ + indent(o, i); genIf(o, "!=", s[0].ub); genGoTo(o, bg); + return; + } else { + indent(o, i); genIf(o, "==", s[0].ub); genGoTo(o, s[1].to); + } + n -= 2; s += 2; + } + if(n == 1){ + if(bg != next){ + indent(o, i); genGoTo(o, s[0].to); + } + return; + } else if(n == 2 && bg == next){ + indent(o, i); genIf(o, ">=", s[0].ub); genGoTo(o, s[1].to); + return; + } else { + indent(o, i); genIf(o, "<=", s[0].ub - 1); genGoTo(o, bg); + n -= 1; s += 1; + } + } +} + +void Go::genLinear(ostream &o, State *next){ + doLinear(o, 0, span, nSpans, next); +} + +void genCases(ostream &o, uint lb, Span *s){ + if(lb < s->ub){ + for(;;){ + o << "\tcase '"; prtCh(o, lb); o << "':"; + if(++lb == s->ub) + break; + o << "\n"; + } + } +} + +void Go::genSwitch(ostream &o, State *next){ + if(nSpans <= 2){ + genLinear(o, next); + } else { + State *def = span[nSpans-1].to; + Span **sP = new Span*[nSpans-1], **r, **s, **t; + + t = &sP[0]; + for(uint i = 0; i < nSpans; ++i) + if(span[i].to != def) + *(t++) = &span[i]; + + o << "\tswitch(yych){\n"; + while(t != &sP[0]){ + r = s = &sP[0]; + if(*s == &span[0]) + genCases(o, 0, *s); + else + genCases(o, (*s)[-1].ub, *s); + State *to = (*s)->to; + while(++s < t){ + if((*s)->to == to) + genCases(o, (*s)[-1].ub, *s); + else + *(r++) = *s; + } + genGoTo(o, to); + t = r; + } + o << "\tdefault:"; + genGoTo(o, def); + o << "\t}\n"; + + delete [] sP; + } +} + +void doBinary(ostream &o, uint i, Span *s, uint n, State *next){ + if(n <= 4){ + doLinear(o, i, s, n, next); + } else { + uint h = n/2; + indent(o, i); genIf(o, "<=", s[h-1].ub - 1); o << "{\n"; + doBinary(o, i+1, &s[0], h, next); + indent(o, i); o << "\t} else {\n"; + doBinary(o, i+1, &s[h], n - h, next); + indent(o, i); o << "\t}\n"; + } +} + +void Go::genBinary(ostream &o, State *next){ + doBinary(o, 0, span, nSpans, next); +} + +void Go::genBase(ostream &o, State *next){ + if(nSpans == 0) + return; + if(!sFlag){ + genSwitch(o, next); + return; + } + if(nSpans > 8){ + Span *bot = &span[0], *top = &span[nSpans-1]; + uint util; + if(bot[0].to == top[0].to){ + util = (top[-1].ub - bot[0].ub)/(nSpans - 2); + } else { + if(bot[0].ub > (top[0].ub - top[-1].ub)){ + util = (top[0].ub - bot[0].ub)/(nSpans - 1); + } else { + util = top[-1].ub/(nSpans - 1); + } + } + if(util <= 2){ + genSwitch(o, next); + return; + } + } + if(nSpans > 5){ + genBinary(o, next); + } else { + genLinear(o, next); + } +} + +void Go::genGoto(ostream &o, State *next){ + if(bFlag){ + for(uint i = 0; i < nSpans; ++i){ + State *to = span[i].to; + if(to && to->isBase){ + BitMap *b = BitMap::find(to); + if(b && matches(b->go, b->on, this, to)){ + Go go; + go.span = new Span[nSpans]; + go.unmap(this, to); + o << "\tif(yybm[" << b->i << "+yych] & " << (uint) b->m << ")"; + genGoTo(o, to); + go.genBase(o, next); + delete [] go.span; + return; + } + } + } + } + genBase(o, next); +} + +void State::emit(ostream &o){ + o << "yy" << label << ":"; + action->emit(o); +} + +uint merge(Span *x0, State *fg, State *bg){ + Span *x = x0, *f = fg->go.span, *b = bg->go.span; + uint nf = fg->go.nSpans, nb = bg->go.nSpans; + State *prev = NULL, *to; + // NB: we assume both spans are for same range + for(;;){ + if(f->ub == b->ub){ + to = f->to == b->to? bg : f->to; + if(to == prev){ + --x; + } else { + x->to = prev = to; + } + x->ub = f->ub; + ++x; ++f; --nf; ++b; --nb; + if(nf == 0 && nb == 0) + return x - x0; + } + while(f->ub < b->ub){ + to = f->to == b->to? bg : f->to; + if(to == prev){ + --x; + } else { + x->to = prev = to; + } + x->ub = f->ub; + ++x; ++f; --nf; + } + while(b->ub < f->ub){ + to = b->to == f->to? bg : f->to; + if(to == prev){ + --x; + } else { + x->to = prev = to; + } + x->ub = b->ub; + ++x; ++b; --nb; + } + } +} + +const uint cInfinity = ~0; + +class SCC { +public: + State **top, **stk; +public: + SCC(uint); + ~SCC(); + void traverse(State*); +}; + +SCC::SCC(uint size){ + top = stk = new State*[size]; +} + +SCC::~SCC(){ + delete [] stk; +} + +void SCC::traverse(State *x){ + *top = x; + uint k = ++top - stk; + x->depth = k; + for(uint i = 0; i < x->go.nSpans; ++i){ + State *y = x->go.span[i].to; + if(y){ + if(y->depth == 0) + traverse(y); + if(y->depth < x->depth) + x->depth = y->depth; + } + } + if(x->depth == k) + do { + (*--top)->depth = cInfinity; + (*top)->link = x; + } while(*top != x); +} + +uint maxDist(State *s){ + uint mm = 0; + for(uint i = 0; i < s->go.nSpans; ++i){ + State *t = s->go.span[i].to; + if(t){ + uint m = 1; + if(!t->link) + m += maxDist(t); + if(m > mm) + mm = m; + } + } + return mm; +} + +void calcDepth(State *head){ + State *t; + for(State *s = head; s; s = s->next){ + if(s->link == s){ + for(uint i = 0; i < s->go.nSpans; ++i){ + t = s->go.span[i].to; + if(t && t->link == s) + goto inSCC; + } + s->link = NULL; + } else { + inSCC: + s->depth = maxDist(s); + } + } +} + +void DFA::findSCCs(){ + SCC scc(nStates); + State *s; + + for(s = head; s; s = s->next){ + s->depth = 0; + s->link = NULL; + } + + for(s = head; s; s = s->next) + if(!s->depth) + scc.traverse(s); + + calcDepth(head); +} + +void DFA::split(State *s){ + State *move = new State; + (void) new Move(move); + addState(&s->next, move); + move->link = s->link; + move->rule = s->rule; + move->go = s->go; + s->rule = NULL; + s->go.nSpans = 1; + s->go.span = new Span[1]; + s->go.span[0].ub = ubChar; + s->go.span[0].to = move; +} + +void DFA::emit(ostream &o){ + static uint label = 0; + State *s; + uint i; + + findSCCs(); + head->link = head; + head->depth = maxDist(head); + + uint nRules = 0; + for(s = head; s; s = s->next) + if(s->rule && s->rule->accept >= nRules) + nRules = s->rule->accept + 1; + + uint nSaves = 0; + uint *saves = new uint[nRules]; + memset(saves, ~0, (nRules)*sizeof(*saves)); + + // mark backtracking points + for(s = head; s; s = s->next){ + RuleOp *ignore = NULL; + if(s->rule){ + for(i = 0; i < s->go.nSpans; ++i) + if(s->go.span[i].to && !s->go.span[i].to->rule){ + delete s->action; + if(saves[s->rule->accept] == ~0u) + saves[s->rule->accept] = nSaves++; + (void) new Save(s, saves[s->rule->accept]); + continue; + } + ignore = s->rule; + } + } + + // insert actions + State **rules = new State*[nRules]; + memset(rules, 0, (nRules)*sizeof(*rules)); + State *accept = NULL; + for(s = head; s; s = s->next){ + State *ow; + if(!s->rule){ + ow = accept; + } else { + if(!rules[s->rule->accept]){ + State *n = new State; + (void) new Rule(n, s->rule); + rules[s->rule->accept] = n; + addState(&s->next, n); + } + ow = rules[s->rule->accept]; + } + for(i = 0; i < s->go.nSpans; ++i) + if(!s->go.span[i].to){ + if(!ow){ + ow = accept = new State; + (void) new Accept(accept, nRules, saves, rules); + addState(&s->next, accept); + } + s->go.span[i].to = ow; + } + } + + // split ``base'' states into two parts + for(s = head; s; s = s->next){ + s->isBase = false; + if(s->link){ + for(i = 0; i < s->go.nSpans; ++i){ + if(s->go.span[i].to == s){ + s->isBase = true; + split(s); + if(bFlag) + BitMap::find(&s->next->go, s); + s = s->next; + break; + } + } + } + } + + // find ``base'' state, if possible + Span *span = new Span[ubChar - lbChar]; + for(s = head; s; s = s->next){ + if(!s->link){ + for(i = 0; i < s->go.nSpans; ++i){ + State *to = s->go.span[i].to; + if(to && to->isBase){ + to = to->go.span[0].to; + uint nSpans = merge(span, s, to); + if(nSpans < s->go.nSpans){ + delete [] s->go.span; + s->go.nSpans = nSpans; + s->go.span = new Span[nSpans]; + memcpy(s->go.span, span, nSpans*sizeof(Span)); + } + break; + } + } + } + } + delete [] span; + + delete head->action; + + o << "{\n\tYYCTYPE yych;\n\tunsigned int yyaccept;\n"; + + if(bFlag) + BitMap::gen(o, lbChar, ubChar); + + o << "\tgoto yy" << label << ";\n"; + (void) new Enter(head, label++); + + for(s = head; s; s = s->next) + s->label = label++; + + for(s = head; s; s = s->next){ + s->emit(o); + s->go.genGoto(o, s->next); + } + o << "}\n"; + + BitMap::first = NULL; + + delete [] saves; + delete [] rules; +} diff --git a/dfa.cc b/dfa.cc new file mode 100644 index 00000000..c1ff0545 --- /dev/null +++ b/dfa.cc @@ -0,0 +1,222 @@ +#include +#include +#include +#include "globals.h" +#include "substr.h" +#include "dfa.h" + +inline char octCh(uint c){ + return '0' + c%8; +} + +void prtCh(ostream &o, uchar c){ + uchar oc = 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(isprint(oc)) + o << (char) oc; + else + o << '\\' << octCh(c/64) << octCh(c/8) << octCh(c); + } +} + +void printSpan(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(ostream &o, uint lb){ + if(to){ + printSpan(o, lb, ub); + o << " " << to->label << "; "; + } + return ub; +} + +ostream& operator<<(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; +} + +ostream& operator<<(ostream &o, const DFA &dfa){ + for(State *s = dfa.head; s; s = s->next) + o << s << "\n\n"; + return o; +} + +State::State() : rule(NULL), link(NULL), kCount(0), kernel(NULL), action(NULL) { + go.nSpans = 0; + go.span = 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 = (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) { + 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)); + tail = &head; + head = NULL; + nStates = 0; + toDo = NULL; + 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; + } + } + + 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){ + *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; +} diff --git a/dfa.h b/dfa.h new file mode 100644 index 00000000..edd018c3 --- /dev/null +++ b/dfa.h @@ -0,0 +1,149 @@ +#ifndef _dfa_h +#define _dfa_h + +#include +#include "re.h" + +extern void prtCh(ostream&, uchar); +extern void printSpan(ostream&, uint, uint); + +class DFA; +class State; + +class Action { +public: + State *state; +public: + Action(State*); + virtual void emit(ostream&) = 0; +}; + +class Match: public Action { +public: + Match(State*); + void emit(ostream&); +}; + +class Enter: public Action { +public: + uint label; +public: + Enter(State*, uint); + void emit(ostream&); +}; + +class Save: public Match { +public: + uint selector; +public: + Save(State*, uint); + void emit(ostream&); +}; + +class Move: public Action { +public: + Move(State*); + void emit(ostream&); +}; + +class Accept: public Action { +public: + uint nRules; + uint *saves; + State **rules; +public: + Accept(State*, uint, uint*, State**); + void emit(ostream&); +}; + +class Rule: public Action { +public: + RuleOp *rule; +public: + Rule(State*, RuleOp*); + void emit(ostream&); +}; + +class Span { +public: + uint ub; + State *to; +public: + uint show(ostream&, uint); +}; + +class Go { +public: + uint nSpans; + Span *span; +public: + void genGoto(ostream&, State*); + void genBase(ostream&, State*); + void genLinear(ostream&, State*); + void genBinary(ostream&, State*); + void genSwitch(ostream&, State*); + void compact(); + void unmap(Go*, State*); +}; + +class State { +public: + uint label; + RuleOp *rule; + State *next; + State *link; + uint depth; // for finding SCCs + uint kCount; + Ins **kernel; + bool isBase:1; + Go go; + Action *action; +public: + State(); + ~State(); + void emit(ostream&); + friend ostream& operator<<(ostream&, const State&); + friend ostream& operator<<(ostream&, const State*); +}; + +class DFA { +public: + uint lbChar; + uint ubChar; + uint nStates; + State *head, **tail; + State *toDo; +public: + DFA(Ins*, uint, uint, uint, Char*); + ~DFA(); + void addState(State**, State*); + State *findState(Ins**, uint); + void split(State*); + + void findSCCs(); + void emit(ostream&); + + friend ostream& operator<<(ostream&, const DFA&); + friend ostream& operator<<(ostream&, const DFA*); +}; + +inline Action::Action(State *s) : state(s) { + s->action = this; +} + +inline Match::Match(State *s) : Action(s) + { } + +inline Enter::Enter(State *s, uint l) : Action(s), label(l) + { } + +inline Save::Save(State *s, uint i) : Match(s), selector(i) + { } + +inline ostream& operator<<(ostream &o, const State *s) + { return o << *s; } + +inline ostream& operator<<(ostream &o, const DFA *dfa) + { return o << *dfa; } + +#endif diff --git a/doc/loplas.ps.gz b/doc/loplas.ps.gz new file mode 100644 index 0000000000000000000000000000000000000000..b0be76bf67aa600cf972c7837ecff9776e64b85c GIT binary patch literal 69079 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

E#JDiIo#a*^X6vp^B3bHKB0jI z$JlVck0ZP-LDQenvI8)qb; zB^b)WavdFfBBgQ{yS}-Jb1WKfGI4J2nC0LOZQkQmv&`W*Sn7QC z=*jtY568-(OK~{m(f|LHFN`re$HOM>Zr%LPPv$>|B+~is@gfEx7lKc&!AJSHfRM6T zlZsKl595%Ep=Qm9))5fCPc`c|(DIQUbjexOwbswQPJTx6*~Qn>(ba0pN75Bv7ymKg zg?`%}RvjNsZzc}sZ}j)|nyv=??{6nGNnhdSiVULX7M%7Jz;ATB?zjXr!w3*#ZHT83 zW4O1zaAa=)(4g=uccUx1Gw<1wmFE{3oOD0Ym8{*bTfLgGs+cr23h=&Z`70WgJCA%) z)Nbd}`gyo=0$is*YqHaH^kuu->>nX=9*Z@HP|*>gN+u5;e-&)T#U7-D@_FM#hiM} z$I|z+!&dFGw>%TY&6o#4`e5>b{>U+8y$M`re#l?7Z-}%Va&9J8>T)^yq2&^N>n+1G z{5auszTN0W&mahS&4GuaoRucb?N)?h+5dtUCSM3#ctHI`zi#FR0YEb-|5y;xLU;l1S%z@3IbIePn^)|3iu zquge1fqatQtgU#~Ql7PTR3^oTGH+zgN@(WSxu3Ha>vaeIeLZ>X;+Ef%zQx!4J^nsE zFgt%aAuWQ&C#a)5$_fLef$dTL?u##2>hLnN(n^1Aga=k!&G5)!dXZL-wH5xWE3>S{b=#YfOy)TCbtk>n|N;A{PJ%Z?{U`=ZZV)lII7j=RZu;IiviA;Rje8@AI_J(tx zN7tpF_PU!y}{*EP1Q3m3O>jCb<+ah)eoL03-ri zxLCx`_!Y)l+i7T?oa`Bd9bx8o}Ug657$4v*3uBO7dhml*FEL@DT!f&1w(ux_W zeYZPKQA?Xx2I7kLS;9g-69(eAF`R2nIEO5n_Oli5v2S&w55>6$m~p6Wiy_nO#Tlhy zdw7UN!6_!z#WM$)oMVlb#3+n>!z|J8aG0SuXpK*{y7`dMelP$wDE`+;><9MEbcYlb z5ym`wG|Mb;b%!%M&UGDTVlfeu_dUiGoEPIR*yt*CyH88qs-BpY7bip#XieYn`MKY} zSEhna^vX%B#ppF-O0D-Kx47-QiIkHURY?{A6~PypBC{I(Fx}4pt13#xK&QYd^9h}T zS+*z(^#Pq(k`*G@1$S_c{7Aa$wGW3jMBsHN9%?gb;h3h0xrM}tj_7B_b zTKDae#^|++pH|&r!?JvZod)GXkwE9>b)wV!jQ}+5kydi|M`}}~M&~o^2AF$Oo9Kqi zXHW^XiO)_R(Q-tK_@T%ObrL5P^!V!}P?f&rT)o-$9r$g|a;LNEw?`lc!$I(O5tOe` z`2be2?(jLA#J~IgM|R-sjsl-#)zLX4Vn0=%+7x-@QrDGwP;iQu8%X{@5O?PVag7|J zPYB|bNMUB@>7E_82ObN6-@kg!%kh&TTghry5HO>M2jm}@8Hwr~+Q>VSZ&E@TF5UZ) zasmop)3gQJ(!Y~Z-7QygIrvfzFE4=Ku#c<*q{UYg;fJ)AquW6zaz5A}Yka(sQuO&^ zZk@2=t|2Y#%?8MCQH1U!QA_%bx?1ktbw(O6mwqg zG;T_bZfe)cIG5*TOdb`ncOo)&2cV$J0Q%+P63}Nstw;{5DRGBv873 z7_UduU%~P%v-~P3P6B@CakFZ}TXiXTZZes-%(ruf+WZ7!E6-*RENJnY7d8Sz+2T7n}`TNct-*@ILu}Kem$8Y_ECzwtJ>_wJNBAXUo zHf0KinKZIXhdVF|wqOr4)*be$L4RJCti8OyXA!pDcgK6V@$hPkNyKi`veM6ciiW9J z0CJ>7C`Gc#N37C!E@xGsVZEKQ;}>UVS_Girl|Y%fglboDeHO{dgrjKHJBl>6q1E%s zdi(=j!8G$T!h0deM5+fhm +#include +#include +#include +#include + +#ifndef MAP_NORESERVE +#define MAP_NORESERVE 0 +#endif + +volatile char ch; + +main(){ + struct stat statbuf; + uchar *buf; + fstat(0, &statbuf); + buf = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED|MAP_NORESERVE, + 0, 0); + if(buf != (uchar*)(-1)){ + uchar *cur, *lim = &buf[statbuf.st_size]; + for(cur = buf; buf != lim; ++cur){ + ch = *cur; + } + munmap(buf, statbuf.st_size); + } +} diff --git a/examples/c.re b/examples/c.re new file mode 100644 index 00000000..419964fb --- /dev/null +++ b/examples/c.re @@ -0,0 +1,272 @@ +#include +#include +#include + +#define ADDEQ 257 +#define ANDAND 258 +#define ANDEQ 259 +#define ARRAY 260 +#define ASM 261 +#define AUTO 262 +#define BREAK 263 +#define CASE 264 +#define CHAR 265 +#define CONST 266 +#define CONTINUE 267 +#define DECR 268 +#define DEFAULT 269 +#define DEREF 270 +#define DIVEQ 271 +#define DO 272 +#define DOUBLE 273 +#define ELLIPSIS 274 +#define ELSE 275 +#define ENUM 276 +#define EQL 277 +#define EXTERN 278 +#define FCON 279 +#define FLOAT 280 +#define FOR 281 +#define FUNCTION 282 +#define GEQ 283 +#define GOTO 284 +#define ICON 285 +#define ID 286 +#define IF 287 +#define INCR 288 +#define INT 289 +#define LEQ 290 +#define LONG 291 +#define LSHIFT 292 +#define LSHIFTEQ 293 +#define MODEQ 294 +#define MULEQ 295 +#define NEQ 296 +#define OREQ 297 +#define OROR 298 +#define POINTER 299 +#define REGISTER 300 +#define RETURN 301 +#define RSHIFT 302 +#define RSHIFTEQ 303 +#define SCON 304 +#define SHORT 305 +#define SIGNED 306 +#define SIZEOF 307 +#define STATIC 308 +#define STRUCT 309 +#define SUBEQ 310 +#define SWITCH 311 +#define TYPEDEF 312 +#define UNION 313 +#define UNSIGNED 314 +#define VOID 315 +#define VOLATILE 316 +#define WHILE 317 +#define XOREQ 318 +#define EOI 319 + +typedef unsigned int uint; +typedef unsigned char uchar; + +#define BSIZE 8192 + +#define YYCTYPE uchar +#define YYCURSOR cursor +#define YYLIMIT s->lim +#define YYMARKER s->ptr +#define YYFILL(n) {cursor = fill(s, cursor);} + +#define RET(i) {s->cur = cursor; return i;} + +typedef struct Scanner { + int fd; + uchar *bot, *tok, *ptr, *cur, *pos, *lim, *top, *eof; + uint line; +} Scanner; + +uchar *fill(Scanner *s, uchar *cursor){ + if(!s->eof){ + uint cnt = s->tok - s->bot; + if(cnt){ + memcpy(s->bot, s->tok, s->lim - s->tok); + s->tok = s->bot; + s->ptr -= cnt; + cursor -= cnt; + s->pos -= cnt; + s->lim -= cnt; + } + if((s->top - s->lim) < BSIZE){ + uchar *buf = (uchar*) malloc(((s->lim - s->bot) + BSIZE)*sizeof(uchar)); + memcpy(buf, s->tok, s->lim - s->tok); + s->tok = buf; + s->ptr = &buf[s->ptr - s->bot]; + cursor = &buf[cursor - s->bot]; + s->pos = &buf[s->pos - s->bot]; + s->lim = &buf[s->lim - s->bot]; + s->top = &s->lim[BSIZE]; + free(s->bot); + s->bot = buf; + } + if((cnt = read(s->fd, (char*) s->lim, BSIZE)) != BSIZE){ + s->eof = &s->lim[cnt]; *(s->eof)++ = '\n'; + } + s->lim += cnt; + } + return cursor; +} + +int scan(Scanner *s){ + uchar *cursor = s->cur; +std: + s->tok = cursor; +/*!re2c +any = [\000-\377]; +O = [0-7]; +D = [0-9]; +L = [a-zA-Z_]; +H = [a-fA-F0-9]; +E = [Ee] [+-]? D+; +FS = [fFlL]; +IS = [uUlL]*; +ESC = [\\] ([abfnrtv?'"\\] | "x" H+ | O+); +*/ + +/*!re2c + "/*" { goto comment; } + + "auto" { RET(AUTO); } + "break" { RET(BREAK); } + "case" { RET(CASE); } + "char" { RET(CHAR); } + "const" { RET(CONST); } + "continue" { RET(CONTINUE); } + "default" { RET(DEFAULT); } + "do" { RET(DO); } + "double" { RET(DOUBLE); } + "else" { RET(ELSE); } + "enum" { RET(ENUM); } + "extern" { RET(EXTERN); } + "float" { RET(FLOAT); } + "for" { RET(FOR); } + "goto" { RET(GOTO); } + "if" { RET(IF); } + "int" { RET(INT); } + "long" { RET(LONG); } + "register" { RET(REGISTER); } + "return" { RET(RETURN); } + "short" { RET(SHORT); } + "signed" { RET(SIGNED); } + "sizeof" { RET(SIZEOF); } + "static" { RET(STATIC); } + "struct" { RET(STRUCT); } + "switch" { RET(SWITCH); } + "typedef" { RET(TYPEDEF); } + "union" { RET(UNION); } + "unsigned" { RET(UNSIGNED); } + "void" { RET(VOID); } + "volatile" { RET(VOLATILE); } + "while" { RET(WHILE); } + + L (L|D)* { RET(ID); } + + ("0" [xX] H+ IS?) | ("0" D+ IS?) | (D+ IS?) | + (['] (ESC|any\[\n\\'])* [']) + { RET(ICON); } + + (D+ E FS?) | (D* "." D+ E? FS?) | (D+ "." D* E? FS?) + { RET(FCON); } + + (["] (ESC|any\[\n\\"])* ["]) + { RET(SCON); } + + "..." { RET(ELLIPSIS); } + ">>=" { RET(RSHIFTEQ); } + "<<=" { RET(LSHIFTEQ); } + "+=" { RET(ADDEQ); } + "-=" { RET(SUBEQ); } + "*=" { RET(MULEQ); } + "/=" { RET(DIVEQ); } + "%=" { RET(MODEQ); } + "&=" { RET(ANDEQ); } + "^=" { RET(XOREQ); } + "|=" { RET(OREQ); } + ">>" { RET(RSHIFT); } + "<<" { RET(LSHIFT); } + "++" { RET(INCR); } + "--" { RET(DECR); } + "->" { RET(DEREF); } + "&&" { RET(ANDAND); } + "||" { RET(OROR); } + "<=" { RET(LEQ); } + ">=" { RET(GEQ); } + "==" { RET(EQL); } + "!=" { RET(NEQ); } + ";" { RET(';'); } + "{" { RET('{'); } + "}" { RET('}'); } + "," { RET(','); } + ":" { RET(':'); } + "=" { RET('='); } + "(" { RET('('); } + ")" { RET(')'); } + "[" { RET('['); } + "]" { RET(']'); } + "." { RET('.'); } + "&" { RET('&'); } + "!" { RET('!'); } + "~" { RET('~'); } + "-" { RET('-'); } + "+" { RET('+'); } + "*" { RET('*'); } + "/" { RET('/'); } + "%" { RET('%'); } + "<" { RET('<'); } + ">" { RET('>'); } + "^" { RET('^'); } + "|" { RET('|'); } + "?" { RET('?'); } + + + [ \t\v\f]+ { goto std; } + + "\n" + { + if(cursor == s->eof) RET(EOI); + s->pos = cursor; s->line++; + goto std; + } + + any + { + printf("unexpected character: %c\n", *s->tok); + goto std; + } +*/ + +comment: +/*!re2c + "*/" { goto std; } + "\n" + { + if(cursor == s->eof) RET(EOI); + s->tok = s->pos = cursor; s->line++; + goto comment; + } + any { goto comment; } +*/ +} + +main(){ + Scanner in; + int t; + memset((char*) &in, 0, sizeof(in)); + in.fd = 0; + while((t = scan(&in)) != EOI){ +/* + printf("%d\t%.*s\n", t, in.cur - in.tok, in.tok); + printf("%d\n", t); +*/ + } + close(in.fd); +} diff --git a/examples/cmmap.re b/examples/cmmap.re new file mode 100644 index 00000000..bc4d498a --- /dev/null +++ b/examples/cmmap.re @@ -0,0 +1,267 @@ +#include +#include +#include +#include +#include + +#define ADDEQ 257 +#define ANDAND 258 +#define ANDEQ 259 +#define ARRAY 260 +#define ASM 261 +#define AUTO 262 +#define BREAK 263 +#define CASE 264 +#define CHAR 265 +#define CONST 266 +#define CONTINUE 267 +#define DECR 268 +#define DEFAULT 269 +#define DEREF 270 +#define DIVEQ 271 +#define DO 272 +#define DOUBLE 273 +#define ELLIPSIS 274 +#define ELSE 275 +#define ENUM 276 +#define EQL 277 +#define EXTERN 278 +#define FCON 279 +#define FLOAT 280 +#define FOR 281 +#define FUNCTION 282 +#define GEQ 283 +#define GOTO 284 +#define ICON 285 +#define ID 286 +#define IF 287 +#define INCR 288 +#define INT 289 +#define LEQ 290 +#define LONG 291 +#define LSHIFT 292 +#define LSHIFTEQ 293 +#define MODEQ 294 +#define MULEQ 295 +#define NEQ 296 +#define OREQ 297 +#define OROR 298 +#define POINTER 299 +#define REGISTER 300 +#define RETURN 301 +#define RSHIFT 302 +#define RSHIFTEQ 303 +#define SCON 304 +#define SHORT 305 +#define SIGNED 306 +#define SIZEOF 307 +#define STATIC 308 +#define STRUCT 309 +#define SUBEQ 310 +#define SWITCH 311 +#define TYPEDEF 312 +#define UNION 313 +#define UNSIGNED 314 +#define VOID 315 +#define VOLATILE 316 +#define WHILE 317 +#define XOREQ 318 +#define EOI 319 + +typedef unsigned int unint; +typedef unsigned char uchar; + +#define YYCTYPE uchar +#define YYCURSOR cursor +#define YYLIMIT s->lim +#define YYMARKER s->ptr +#define YYFILL(n) {cursor = fill(s, cursor);} + +#define RET(i) {s->cur = cursor; return i;} + +typedef struct Scanner { + uchar *tok, *ptr, *cur, *pos, *lim, *eof; + unint line; +} Scanner; + +uchar *fill(Scanner *s, uchar *cursor){ + if(!s->eof){ + unint cnt = s->lim - s->tok; + uchar *buf = malloc((cnt + 1)*sizeof(uchar)); + memcpy(buf, s->tok, cnt); + cursor = &buf[cursor - s->tok]; + s->pos = &buf[s->pos - s->tok]; + s->ptr = &buf[s->ptr - s->tok]; + s->lim = &buf[cnt]; + s->eof = s->lim; *(s->eof)++ = '\n'; + s->tok = buf; + } + return cursor; +} + +int scan(Scanner *s){ + uchar *cursor = s->cur; +std: + s->tok = cursor; +/*!re2c +any = [\000-\377]; +O = [0-7]; +D = [0-9]; +L = [a-zA-Z_]; +H = [a-fA-F0-9]; +E = [Ee] [+-]? D+; +FS = [fFlL]; +IS = [uUlL]*; +ESC = [\\] ([abfnrtv?'"\\] | "x" H+ | O+); +*/ + +/*!re2c + "/*" { goto comment; } + + "auto" { RET(AUTO); } + "break" { RET(BREAK); } + "case" { RET(CASE); } + "char" { RET(CHAR); } + "const" { RET(CONST); } + "continue" { RET(CONTINUE); } + "default" { RET(DEFAULT); } + "do" { RET(DO); } + "double" { RET(DOUBLE); } + "else" { RET(ELSE); } + "enum" { RET(ENUM); } + "extern" { RET(EXTERN); } + "float" { RET(FLOAT); } + "for" { RET(FOR); } + "goto" { RET(GOTO); } + "if" { RET(IF); } + "int" { RET(INT); } + "long" { RET(LONG); } + "register" { RET(REGISTER); } + "return" { RET(RETURN); } + "short" { RET(SHORT); } + "signed" { RET(SIGNED); } + "sizeof" { RET(SIZEOF); } + "static" { RET(STATIC); } + "struct" { RET(STRUCT); } + "switch" { RET(SWITCH); } + "typedef" { RET(TYPEDEF); } + "union" { RET(UNION); } + "unsigned" { RET(UNSIGNED); } + "void" { RET(VOID); } + "volatile" { RET(VOLATILE); } + "while" { RET(WHILE); } + + L (L|D)* { RET(ID); } + + ("0" [xX] H+ IS?) | ("0" D+ IS?) | (D+ IS?) | + (['] (ESC|any\[\n\\'])* [']) + { RET(ICON); } + + (D+ E FS?) | (D* "." D+ E? FS?) | (D+ "." D* E? FS?) + { RET(FCON); } + + (["] (ESC|any\[\n\\"])* ["]) + { RET(SCON); } + + "..." { RET(ELLIPSIS); } + ">>=" { RET(RSHIFTEQ); } + "<<=" { RET(LSHIFTEQ); } + "+=" { RET(ADDEQ); } + "-=" { RET(SUBEQ); } + "*=" { RET(MULEQ); } + "/=" { RET(DIVEQ); } + "%=" { RET(MODEQ); } + "&=" { RET(ANDEQ); } + "^=" { RET(XOREQ); } + "|=" { RET(OREQ); } + ">>" { RET(RSHIFT); } + "<<" { RET(LSHIFT); } + "++" { RET(INCR); } + "--" { RET(DECR); } + "->" { RET(DEREF); } + "&&" { RET(ANDAND); } + "||" { RET(OROR); } + "<=" { RET(LEQ); } + ">=" { RET(GEQ); } + "==" { RET(EQL); } + "!=" { RET(NEQ); } + ";" { RET(';'); } + "{" { RET('{'); } + "}" { RET('}'); } + "," { RET(','); } + ":" { RET(':'); } + "=" { RET('='); } + "(" { RET('('); } + ")" { RET(')'); } + "[" { RET('['); } + "]" { RET(']'); } + "." { RET('.'); } + "&" { RET('&'); } + "!" { RET('!'); } + "~" { RET('~'); } + "-" { RET('-'); } + "+" { RET('+'); } + "*" { RET('*'); } + "/" { RET('/'); } + "%" { RET('%'); } + "<" { RET('<'); } + ">" { RET('>'); } + "^" { RET('^'); } + "|" { RET('|'); } + "?" { RET('?'); } + + + [ \t\v\f]+ { goto std; } + + "\n" + { + if(cursor == s->eof) RET(EOI); + s->pos = cursor; s->line++; + goto std; + } + + any + { + printf("unexpected character: %c\n", *s->tok); + goto std; + } +*/ + +comment: +/*!re2c + "*/" { goto std; } + "\n" + { + if(cursor == s->eof) RET(EOI); + s->tok = s->pos = cursor; s->line++; + goto comment; + } + any { goto comment; } +*/ +} + +#ifndef MAP_NORESERVE +#define MAP_NORESERVE 0 +#endif + +main(){ + Scanner in; + struct stat statbuf; + uchar *buf; + fstat(0, &statbuf); + buf = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED|MAP_NORESERVE, + 0, 0); + if(buf != (uchar*)(-1)){ + int t; + in.lim = &(in.cur = buf)[statbuf.st_size]; + in.pos = NULL; + in.eof = NULL; + while((t = scan(&in)) != EOI){ +/* + printf("%d\t%.*s\n", t, in.cur - in.tok, in.tok); + printf("%d\n", t); +*/ + } + munmap(buf, statbuf.st_size); + } +} diff --git a/examples/cnokw.re b/examples/cnokw.re new file mode 100644 index 00000000..bdc12793 --- /dev/null +++ b/examples/cnokw.re @@ -0,0 +1,239 @@ +#include +#include +#include + +#define ADDEQ 257 +#define ANDAND 258 +#define ANDEQ 259 +#define ARRAY 260 +#define ASM 261 +#define AUTO 262 +#define BREAK 263 +#define CASE 264 +#define CHAR 265 +#define CONST 266 +#define CONTINUE 267 +#define DECR 268 +#define DEFAULT 269 +#define DEREF 270 +#define DIVEQ 271 +#define DO 272 +#define DOUBLE 273 +#define ELLIPSIS 274 +#define ELSE 275 +#define ENUM 276 +#define EQL 277 +#define EXTERN 278 +#define FCON 279 +#define FLOAT 280 +#define FOR 281 +#define FUNCTION 282 +#define GEQ 283 +#define GOTO 284 +#define ICON 285 +#define ID 286 +#define IF 287 +#define INCR 288 +#define INT 289 +#define LEQ 290 +#define LONG 291 +#define LSHIFT 292 +#define LSHIFTEQ 293 +#define MODEQ 294 +#define MULEQ 295 +#define NEQ 296 +#define OREQ 297 +#define OROR 298 +#define POINTER 299 +#define REGISTER 300 +#define RETURN 301 +#define RSHIFT 302 +#define RSHIFTEQ 303 +#define SCON 304 +#define SHORT 305 +#define SIGNED 306 +#define SIZEOF 307 +#define STATIC 308 +#define STRUCT 309 +#define SUBEQ 310 +#define SWITCH 311 +#define TYPEDEF 312 +#define UNION 313 +#define UNSIGNED 314 +#define VOID 315 +#define VOLATILE 316 +#define WHILE 317 +#define XOREQ 318 +#define EOI 319 + +typedef unsigned int uint; +typedef unsigned char uchar; + +#define BSIZE 8192 + +#define YYCTYPE uchar +#define YYCURSOR cursor +#define YYLIMIT s->lim +#define YYMARKER s->ptr +#define YYFILL(n) {cursor = fill(s, cursor);} + +#define RET(i) {s->cur = cursor; return i;} + +typedef struct Scanner { + int fd; + uchar *bot, *tok, *ptr, *cur, *pos, *lim, *top, *eof; + uint line; +} Scanner; + +uchar *fill(Scanner *s, uchar *cursor){ + if(!s->eof){ + uint cnt = s->tok - s->bot; + if(cnt){ + memcpy(s->bot, s->tok, s->lim - s->tok); + s->tok = s->bot; + s->ptr -= cnt; + cursor -= cnt; + s->pos -= cnt; + s->lim -= cnt; + } + if((s->top - s->lim) < BSIZE){ + uchar *buf = (uchar*) malloc(((s->lim - s->bot) + BSIZE)*sizeof(uchar)); + memcpy(buf, s->tok, s->lim - s->tok); + s->tok = buf; + s->ptr = &buf[s->ptr - s->bot]; + cursor = &buf[cursor - s->bot]; + s->pos = &buf[s->pos - s->bot]; + s->lim = &buf[s->lim - s->bot]; + s->top = &s->lim[BSIZE]; + free(s->bot); + s->bot = buf; + } + if((cnt = read(s->fd, (char*) s->lim, BSIZE)) != BSIZE){ + s->eof = &s->lim[cnt]; *(s->eof)++ = '\n'; + } + s->lim += cnt; + } + return cursor; +} + +int scan(Scanner *s){ + uchar *cursor = s->cur; +std: + s->tok = cursor; +/*!re2c +any = [\000-\377]; +O = [0-7]; +D = [0-9]; +L = [a-zA-Z_]; +H = [a-fA-F0-9]; +E = [Ee] [+-]? D+; +FS = [fFlL]; +IS = [uUlL]*; +ESC = [\\] ([abfnrtv?'"\\] | "x" H+ | O+); +*/ + +/*!re2c + "/*" { goto comment; } + + L (L|D)* { RET(ID); } + + ("0" [xX] H+ IS?) | ("0" D+ IS?) | (D+ IS?) | + (['] (ESC|any\[\n\\'])* [']) + { RET(ICON); } + + (D+ E FS?) | (D* "." D+ E? FS?) | (D+ "." D* E? FS?) + { RET(FCON); } + + (["] (ESC|any\[\n\\"])* ["]) + { RET(SCON); } + + "..." { RET(ELLIPSIS); } + ">>=" { RET(RSHIFTEQ); } + "<<=" { RET(LSHIFTEQ); } + "+=" { RET(ADDEQ); } + "-=" { RET(SUBEQ); } + "*=" { RET(MULEQ); } + "/=" { RET(DIVEQ); } + "%=" { RET(MODEQ); } + "&=" { RET(ANDEQ); } + "^=" { RET(XOREQ); } + "|=" { RET(OREQ); } + ">>" { RET(RSHIFT); } + "<<" { RET(LSHIFT); } + "++" { RET(INCR); } + "--" { RET(DECR); } + "->" { RET(DEREF); } + "&&" { RET(ANDAND); } + "||" { RET(OROR); } + "<=" { RET(LEQ); } + ">=" { RET(GEQ); } + "==" { RET(EQL); } + "!=" { RET(NEQ); } + ";" { RET(';'); } + "{" { RET('{'); } + "}" { RET('}'); } + "," { RET(','); } + ":" { RET(':'); } + "=" { RET('='); } + "(" { RET('('); } + ")" { RET(')'); } + "[" { RET('['); } + "]" { RET(']'); } + "." { RET('.'); } + "&" { RET('&'); } + "!" { RET('!'); } + "~" { RET('~'); } + "-" { RET('-'); } + "+" { RET('+'); } + "*" { RET('*'); } + "/" { RET('/'); } + "%" { RET('%'); } + "<" { RET('<'); } + ">" { RET('>'); } + "^" { RET('^'); } + "|" { RET('|'); } + "?" { RET('?'); } + + + [ \t\v\f]+ { goto std; } + + "\n" + { + if(cursor == s->eof) RET(EOI); + s->pos = cursor; s->line++; + goto std; + } + + any + { + printf("unexpected character: %c\n", *s->tok); + goto std; + } +*/ + +comment: +/*!re2c + "*/" { goto std; } + "\n" + { + if(cursor == s->eof) RET(EOI); + s->tok = s->pos = cursor; s->line++; + goto comment; + } + any { goto comment; } +*/ +} + +main(){ + Scanner in; + int t; + memset((char*) &in, 0, sizeof(in)); + in.fd = 0; + while((t = scan(&in)) != EOI){ +/* + printf("%d\t%.*s\n", t, in.cur - in.tok, in.tok); + printf("%d\n", t); +*/ + } + close(in.fd); +} diff --git a/examples/cunroll.re b/examples/cunroll.re new file mode 100644 index 00000000..dd9d8054 --- /dev/null +++ b/examples/cunroll.re @@ -0,0 +1,258 @@ +#include +#include +#include + +#define ADDEQ 257 +#define ANDAND 258 +#define ANDEQ 259 +#define ARRAY 260 +#define ASM 261 +#define AUTO 262 +#define BREAK 263 +#define CASE 264 +#define CHAR 265 +#define CONST 266 +#define CONTINUE 267 +#define DECR 268 +#define DEFAULT 269 +#define DEREF 270 +#define DIVEQ 271 +#define DO 272 +#define DOUBLE 273 +#define ELLIPSIS 274 +#define ELSE 275 +#define ENUM 276 +#define EQL 277 +#define EXTERN 278 +#define FCON 279 +#define FLOAT 280 +#define FOR 281 +#define FUNCTION 282 +#define GEQ 283 +#define GOTO 284 +#define ICON 285 +#define ID 286 +#define IF 287 +#define INCR 288 +#define INT 289 +#define LEQ 290 +#define LONG 291 +#define LSHIFT 292 +#define LSHIFTEQ 293 +#define MODEQ 294 +#define MULEQ 295 +#define NEQ 296 +#define OREQ 297 +#define OROR 298 +#define POINTER 299 +#define REGISTER 300 +#define RETURN 301 +#define RSHIFT 302 +#define RSHIFTEQ 303 +#define SCON 304 +#define SHORT 305 +#define SIGNED 306 +#define SIZEOF 307 +#define STATIC 308 +#define STRUCT 309 +#define SUBEQ 310 +#define SWITCH 311 +#define TYPEDEF 312 +#define UNION 313 +#define UNSIGNED 314 +#define VOID 315 +#define VOLATILE 316 +#define WHILE 317 +#define XOREQ 318 +#define EOI 319 + +typedef unsigned int uint; +typedef unsigned char uchar; + +#define BSIZE 8192 + +#define YYCTYPE uchar +#define YYCURSOR cursor +#define YYLIMIT s->lim +#define YYMARKER s->ptr +#define YYFILL(n) {cursor = fill(s, cursor);} + +#define RET(i) {s->cur = cursor; return i;} + +typedef struct Scanner { + int fd; + uchar *bot, *tok, *ptr, *cur, *pos, *lim, *top, *eof; + uint line; +} Scanner; + +uchar *fill(Scanner *s, uchar *cursor){ + if(!s->eof){ + uint cnt = s->tok - s->bot; + if(cnt){ + memcpy(s->bot, s->tok, s->lim - s->tok); + s->tok = s->bot; + s->ptr -= cnt; + cursor -= cnt; + s->pos -= cnt; + s->lim -= cnt; + } + if((s->top - s->lim) < BSIZE){ + uchar *buf = (uchar*) malloc(((s->lim - s->bot) + BSIZE)*sizeof(uchar)); + memcpy(buf, s->tok, s->lim - s->tok); + s->tok = buf; + s->ptr = &buf[s->ptr - s->bot]; + cursor = &buf[cursor - s->bot]; + s->pos = &buf[s->pos - s->bot]; + s->lim = &buf[s->lim - s->bot]; + s->top = &s->lim[BSIZE]; + free(s->bot); + s->bot = buf; + } + if((cnt = read(s->fd, (char*) s->lim, BSIZE)) != BSIZE){ + s->eof = &s->lim[cnt]; *(s->eof)++ = '\n'; + } + s->lim += cnt; + } + return cursor; +} + +int scan(Scanner *s){ + uchar *cursor = s->cur; +std: + s->tok = cursor; +/*!re2c +any = [\000-\377]; +O = [0-7]; +D = [0-9]; +L = [a-zA-Z_]; +I = L|D; +H = [a-fA-F0-9]; +E = [Ee] [+-]? D+; +FS = [fFlL]; +IS = [uUlL]*; +ESC = [\\] ([abfnrtv?'"\\] | "x" H+ | O+); +X = any\[*/]; +*/ + +/*!re2c + "/*" { goto comment; } + + + L { RET(ID); } + L I { RET(ID); } + L I I { RET(ID); } + L I I I { RET(ID); } + L I I I I { RET(ID); } + L I I I I I { RET(ID); } + L I I I I I I { RET(ID); } + L I I I I I I I { RET(ID); } + L I* { RET(ID); } + + ("0" [xX] H+ IS?) | ("0" D+ IS?) | (D+ IS?) | + (['] (ESC|any\[\n\\'])* [']) + { RET(ICON); } + + (D+ E FS?) | (D* "." D+ E? FS?) | (D+ "." D* E? FS?) + { RET(FCON); } + + (["] (ESC|any\[\n\\"])* ["]) + { RET(SCON); } + + "..." { RET(ELLIPSIS); } + ">>=" { RET(RSHIFTEQ); } + "<<=" { RET(LSHIFTEQ); } + "+=" { RET(ADDEQ); } + "-=" { RET(SUBEQ); } + "*=" { RET(MULEQ); } + "/=" { RET(DIVEQ); } + "%=" { RET(MODEQ); } + "&=" { RET(ANDEQ); } + "^=" { RET(XOREQ); } + "|=" { RET(OREQ); } + ">>" { RET(RSHIFT); } + "<<" { RET(LSHIFT); } + "++" { RET(INCR); } + "--" { RET(DECR); } + "->" { RET(DEREF); } + "&&" { RET(ANDAND); } + "||" { RET(OROR); } + "<=" { RET(LEQ); } + ">=" { RET(GEQ); } + "==" { RET(EQL); } + "!=" { RET(NEQ); } + ";" { RET(';'); } + "{" { RET('{'); } + "}" { RET('}'); } + "," { RET(','); } + ":" { RET(':'); } + "=" { RET('='); } + "(" { RET('('); } + ")" { RET(')'); } + "[" { RET('['); } + "]" { RET(']'); } + "." { RET('.'); } + "&" { RET('&'); } + "!" { RET('!'); } + "~" { RET('~'); } + "-" { RET('-'); } + "+" { RET('+'); } + "*" { RET('*'); } + "/" { RET('/'); } + "%" { RET('%'); } + "<" { RET('<'); } + ">" { RET('>'); } + "^" { RET('^'); } + "|" { RET('|'); } + "?" { RET('?'); } + + + [ \t\v\f]+ { goto std; } + + "\n" + { + if(cursor == s->eof) RET(EOI); + s->pos = cursor; s->line++; + goto std; + } + + any + { + printf("unexpected character: %c\n", *s->tok); + goto std; + } +*/ + +comment: +/*!re2c + "*/" { goto std; } + "\n" + { + if(cursor == s->eof) RET(EOI); + s->tok = s->pos = cursor; s->line++; + goto comment; + } + X { goto comment; } + X X { goto comment; } + X X X { goto comment; } + X X X X { goto comment; } + X X X X X { goto comment; } + X X X X X X { goto comment; } + X X X X X X X { goto comment; } + X X X X X X X X { goto comment; } + any { goto comment; } +*/ +} + +main(){ + Scanner in; + int t; + memset((char*) &in, 0, sizeof(in)); + in.fd = 0; + while((t = scan(&in)) != EOI){ +/* + printf("%d\t%.*s\n", t, in.cur - in.tok, in.tok); + printf("%d\n", t); +*/ + } + close(in.fd); +} diff --git a/examples/modula.re b/examples/modula.re new file mode 100644 index 00000000..0468ba4e --- /dev/null +++ b/examples/modula.re @@ -0,0 +1,202 @@ +#include +#include +#include + +typedef unsigned int uint; +typedef unsigned char uchar; + +#define BSIZE 8192 + +#define YYCTYPE uchar +#define YYCURSOR cursor +#define YYLIMIT s->lim +#define YYMARKER s->ptr +#define YYFILL {cursor = fill(s, cursor);} + +#define RETURN(i) {s->cur = cursor; return i;} + +typedef struct Scanner { + int fd; + uchar *bot, *tok, *ptr, *cur, *pos, *lim, *top, *eof; + uint line; +} Scanner; + +uchar *fill(Scanner *s, uchar *cursor){ + if(!s->eof){ + uint cnt = s->tok - s->bot; + if(cnt){ + memcpy(s->bot, s->tok, s->lim - s->tok); + s->tok = s->bot; + s->ptr -= cnt; + cursor -= cnt; + s->pos -= cnt; + s->lim -= cnt; + } + if((s->top - s->lim) < BSIZE){ + uchar *buf = (uchar*) malloc(((s->lim - s->bot) + BSIZE)*sizeof(uchar)); + memcpy(buf, s->tok, s->lim - s->tok); + s->tok = buf; + s->ptr = &buf[s->ptr - s->bot]; + cursor = &buf[cursor - s->bot]; + s->pos = &buf[s->pos - s->bot]; + s->lim = &buf[s->lim - s->bot]; + s->top = &s->lim[BSIZE]; + free(s->bot); + s->bot = buf; + } + if((cnt = read(s->fd, (char*) s->lim, BSIZE)) != BSIZE){ + s->eof = &s->lim[cnt]; *(s->eof)++ = '\n'; + } + s->lim += cnt; + } + return cursor; +} + +int scan(Scanner *s){ + uchar *cursor = s->cur; + uint depth; +std: + s->tok = cursor; +/*!re2c +any = [\000-\377]; +digit = [0-9]; +letter = [a-zA-Z]; +*/ + +/*!re2c + "(*" { depth = 1; goto comment; } + + digit + {RETURN(1);} + digit + / ".." {RETURN(1);} + [0-7] + "B" {RETURN(2);} + [0-7] + "C" {RETURN(3);} + digit [0-9A-F] * "H" {RETURN(4);} + digit + "." digit * ("E" ([+-]) ? digit +) ? {RETURN(5);} + ['] (any\[\n']) * ['] | ["] (any\[\n"]) * ["] {RETURN(6);} + + "#" {RETURN(7);} + "&" {RETURN(8);} + "(" {RETURN(9);} + ")" {RETURN(10);} + "*" {RETURN(11);} + "+" {RETURN(12);} + "," {RETURN(13);} + "-" {RETURN(14);} + "." {RETURN(15);} + ".." {RETURN(16);} + "/" {RETURN(17);} + ":" {RETURN(18);} + ":=" {RETURN(19);} + ";" {RETURN(20);} + "<" {RETURN(21);} + "<=" {RETURN(22);} + "<>" {RETURN(23);} + "=" {RETURN(24);} + ">" {RETURN(25);} + ">=" {RETURN(26);} + "[" {RETURN(27);} + "]" {RETURN(28);} + "^" {RETURN(29);} + "{" {RETURN(30);} + "|" {RETURN(31);} + "}" {RETURN(32);} + "~" {RETURN(33);} + + "AND" {RETURN(34);} + "ARRAY" {RETURN(35);} + "BEGIN" {RETURN(36);} + "BY" {RETURN(37);} + "CASE" {RETURN(38);} + "CONST" {RETURN(39);} + "DEFINITION" {RETURN(40);} + "DIV" {RETURN(41);} + "DO" {RETURN(42);} + "ELSE" {RETURN(43);} + "ELSIF" {RETURN(44);} + "END" {RETURN(45);} + "EXIT" {RETURN(46);} + "EXPORT" {RETURN(47);} + "FOR" {RETURN(48);} + "FROM" {RETURN(49);} + "IF" {RETURN(50);} + "IMPLEMENTATION" {RETURN(51);} + "IMPORT" {RETURN(52);} + "IN" {RETURN(53);} + "LOOP" {RETURN(54);} + "MOD" {RETURN(55);} + "MODULE" {RETURN(56);} + "NOT" {RETURN(57);} + "OF" {RETURN(58);} + "OR" {RETURN(59);} + "POINTER" {RETURN(60);} + "PROCEDURE" {RETURN(61);} + "QUALIFIED" {RETURN(62);} + "RECORD" {RETURN(63);} + "REPEAT" {RETURN(64);} + "RETURN" {RETURN(65);} + "SET" {RETURN(66);} + "THEN" {RETURN(67);} + "TO" {RETURN(68);} + "TYPE" {RETURN(69);} + "UNTIL" {RETURN(70);} + "VAR" {RETURN(71);} + "WHILE" {RETURN(72);} + "WITH" {RETURN(73);} + + letter (letter | digit) * {RETURN(74);} + + [ \t]+ { goto std; } + + "\n" + { + if(cursor == s->eof) RETURN(0); + s->pos = cursor; s->line++; + goto std; + } + + any + { + printf("unexpected character: %c\n", *s->tok); + goto std; + } +*/ +comment: +/*!re2c + "*)" + { + if(--depth == 0) + goto std; + else + goto comment; + } + "(*" { ++depth; goto comment; } + "\n" + { + if(cursor == s->eof) RETURN(0); + s->tok = s->pos = cursor; s->line++; + goto comment; + } + any { goto comment; } +*/ +} + +/* +void putStr(FILE *o, char *s, uint l){ + while(l-- > 0) + putc(*s++, o); +} +*/ + +main(){ + Scanner in; + memset((char*) &in, 0, sizeof(in)); + in.fd = 0; + while(scan(&in)){ +/* + putc('<', stdout); + putStr(stdout, (char*) in.tok, in.cur - in.tok); + putc('>', stdout); + putc('\n', stdout); +*/ + } +} diff --git a/examples/rexx/README b/examples/rexx/README new file mode 100644 index 00000000..2af0178d --- /dev/null +++ b/examples/rexx/README @@ -0,0 +1 @@ +Replacement modules for an existing REXX interpreter. Not standalone. diff --git a/examples/rexx/rexx.l b/examples/rexx/rexx.l new file mode 100644 index 00000000..b74741da --- /dev/null +++ b/examples/rexx/rexx.l @@ -0,0 +1,319 @@ +#include "scanio.h" +#include "scanner.h" + +#define CURSOR ch +#define LOADCURSOR ch = *cursor; +#define ADVANCE cursor++; +#define BACK(n) cursor -= (n); +#define CHECK(n) if((ScanCB.lim - cursor) < (n)){cursor = ScanFill(cursor);} +#define MARK(n) ScanCB.ptr = cursor; sel = (n); +#define REVERT cursor = ScanCB.ptr; +#define MARKER sel + +#define RETURN(i) {ScanCB.cur = cursor; return i;} + +int ScanToken(){ + uchar *cursor = ScanCB.cur; + unsigned sel; + uchar ch; + ScanCB.tok = cursor; + ScanCB.eot = NULL; +/*!re2c +all = [\000-\377]; +eof = [\000]; +any = all\eof; +letter = [a-z]|[A-Z]; +digit = [0-9]; +symchr = letter|digit|[.!?_]; +const = (digit|[.])symchr*([eE][+-]?digit+)?; +simple = (symchr\(digit|[.]))(symchr\[.])*; +stem = simple [.]; +symbol = symchr*; +sqstr = ['] ((any\['\n])|(['][']))* [']; +dqstr = ["] ((any\["\n])|(["]["]))* ["]; +str = sqstr|dqstr; +ob = [ \t]*; +not = [\\~]; +A = [aA]; +B = [bB]; +C = [cC]; +D = [dD]; +E = [eE]; +F = [fF]; +G = [gG]; +H = [hH]; +I = [iI]; +J = [jJ]; +K = [kK]; +L = [lL]; +M = [mM]; +N = [nN]; +O = [oO]; +P = [pP]; +Q = [qQ]; +R = [rR]; +S = [sS]; +T = [tT]; +U = [uU]; +V = [vV]; +W = [wW]; +X = [xX]; +Y = [yY]; +Z = [zZ]; +*/ + +scan: +/*!re2c +"\n" + { + ++(ScanCB.lineNum); + ScanCB.linePos = ScanCB.pos + (cursor - ScanCB.mrk); + RETURN(SU_EOL); + } +"|" ob "|" + { RETURN(OP_CONCAT); } +"+" + { RETURN(OP_PLUS); } +"-" + { RETURN(OP_MINUS); } +"*" + { RETURN(OP_MULT); } +"/" + { RETURN(OP_DIV); } +"%" + { RETURN(OP_IDIV); } +"/" ob "/" + { RETURN(OP_REMAIN); } +"*" ob "*" + { RETURN(OP_POWER); } +"=" + { RETURN(OP_EQUAL); } +not ob "=" | "<" ob ">" | ">" ob "<" + { RETURN(OP_EQUAL_N); } +">" + { RETURN(OP_GT); } +"<" + { RETURN(OP_LT); } +">" ob "=" | not ob "<" + { RETURN(OP_GE); } +"<" ob "=" | not ob ">" + { RETURN(OP_LE); } +"=" ob "=" + { RETURN(OP_EQUAL_EQ); } +not ob "=" ob "=" + { RETURN(OP_EQUAL_EQ_N); } +">" ob ">" + { RETURN(OP_GT_STRICT); } +"<" ob "<" + { RETURN(OP_LT_STRICT); } +">" ob ">" ob "=" | not ob "<" ob "<" + { RETURN(OP_GE_STRICT); } +"<" ob "<" ob "=" | not ob ">" ob ">" + { RETURN(OP_LE_STRICT); } +"&" + { RETURN(OP_AND); } +"|" + { RETURN(OP_OR); } +"&" ob "&" + { RETURN(OP_XOR); } +not + { RETURN(OP_NOT); } + +":" + { RETURN(SU_COLON); } +"," + { RETURN(SU_COMMA); } +"(" + { RETURN(SU_POPEN); } +")" + { RETURN(SU_PCLOSE); } +";" + { RETURN(SU_EOC); } + +A D D R E S S + { RETURN(RX_ADDRESS); } +A R G + { RETURN(RX_ARG); } +C A L L + { RETURN(RX_CALL); } +D O + { RETURN(RX_DO); } +D R O P + { RETURN(RX_DROP); } +E L S E + { RETURN(RX_ELSE); } +E N D + { RETURN(RX_END); } +E X I T + { RETURN(RX_EXIT); } +I F + { RETURN(RX_IF); } +I N T E R P R E T + { RETURN(RX_INTERPRET); } +I T E R A T E + { RETURN(RX_ITERATE); } +L E A V E + { RETURN(RX_LEAVE); } +N O P + { RETURN(RX_NOP); } +N U M E R I C + { RETURN(RX_NUMERIC); } +O P T I O N S + { RETURN(RX_OPTIONS); } +O T H E R W I S E + { RETURN(RX_OTHERWISE); } +P A R S E + { RETURN(RX_PARSE); } +P R O C E D U R E + { RETURN(RX_PROCEDURE); } +P U L L + { RETURN(RX_PULL); } +P U S H + { RETURN(RX_PUSH); } +Q U E U E + { RETURN(RX_QUEUE); } +R E T U R N + { RETURN(RX_RETURN); } +S A Y + { RETURN(RX_SAY); } +S E L E C T + { RETURN(RX_SELECT); } +S I G N A L + { RETURN(RX_SIGNAL); } +T H E N + { RETURN(RX_THEN); } +T R A C E + { RETURN(RX_TRACE); } +W H E N + { RETURN(RX_WHEN); } +O F F + { RETURN(RXS_OFF); } +O N + { RETURN(RXS_ON); } +B Y + { RETURN(RXS_BY); } +D I G I T S + { RETURN(RXS_DIGITS); } +E N G I N E E R I N G + { RETURN(RXS_ENGINEERING); } +E R R O R + { RETURN(RXS_ERROR); } +E X P O S E + { RETURN(RXS_EXPOSE); } +F A I L U R E + { RETURN(RXS_FAILURE); } +F O R + { RETURN(RXS_FOR); } +F O R E V E R + { RETURN(RXS_FOREVER); } +F O R M + { RETURN(RXS_FORM); } +F U Z Z + { RETURN(RXS_FUZZ); } +H A L T + { RETURN(RXS_HALT); } +L I N E I N + { RETURN(RXS_LINEIN); } +N A M E + { RETURN(RXS_NAME); } +N O T R E A D Y + { RETURN(RXS_NOTREADY); } +N O V A L U E + { RETURN(RXS_NOVALUE); } +S C I E N T I F I C + { RETURN(RXS_SCIENTIFIC); } +S O U R C E + { RETURN(RXS_SOURCE); } +S Y N T A X + { RETURN(RXS_SYNTAX); } +T O + { RETURN(RXS_TO); } +U N T I L + { RETURN(RXS_UNTIL); } +U P P E R + { RETURN(RXS_UPPER); } +V A L U E + { RETURN(RXS_VALUE); } +V A R + { RETURN(RXS_VAR); } +V E R S I O N + { RETURN(RXS_VERSION); } +W H I L E + { RETURN(RXS_WHILE); } +W I T H + { RETURN(RXS_WITH); } + +const + { RETURN(SU_CONST); } +simple + { RETURN(SU_SYMBOL); } +stem + { RETURN(SU_SYMBOL_STEM); } +symbol + { RETURN(SU_SYMBOL_COMPOUND); } +str + { RETURN(SU_LITERAL); } +str [bB] / (all\symchr) + { RETURN(SU_LITERAL_BIN); } +str [xX] / (all\symchr) + { RETURN(SU_LITERAL_HEX); } + +eof + { RETURN(SU_EOF); } +any + { RETURN(SU_ERROR); } +*/ +} + +bool StripToken(){ + uchar *cursor = ScanCB.cur; + unsigned depth; + uchar ch; + bool blanks = FALSE; + ScanCB.eot = cursor; +strip: +/*!re2c +"/*" + { + depth = 1; + goto comment; + } +"\r" + { goto strip; } +[ \t] + { + blanks = TRUE; + goto strip; + } +[] / all + { RETURN(blanks); } +*/ + +comment: +/*!re2c +"*/" + { + if(--depth == 0) + goto strip; + else + goto comment; + } +"\n" + { + ++(ScanCB.lineNum); + ScanCB.linePos = ScanCB.pos + (cursor - ScanCB.mrk); + goto comment; + } +"/*" + { + ++depth; + goto comment; + } +eof + { RETURN(blanks); } +any + { + goto comment; + } +*/ +} diff --git a/examples/rexx/scanio.c b/examples/rexx/scanio.c new file mode 100644 index 00000000..de6898df --- /dev/null +++ b/examples/rexx/scanio.c @@ -0,0 +1,41 @@ +uchar *ScanFill(uchar *cursor){ + unsigned cnt = s->tok - s->bot; + s->pos += cursor - s->mrk; + if(cnt){ + if(s->eot){ + unsigned len = s->eot - s->tok; + memcpy(s->bot, s->tok, len); + s->eot = &s->bot[len]; + if((len = s->lim - cursor) != 0) + memcpy(s->eot, cursor, len); + cursor = s->eot; + s->lim = &cursor[len]; + } else { + memcpy(s->bot, s->tok, s->lim - s->tok); + cursor -= cnt; + s->lim -= cnt; + } + s->tok = s->bot; + s->ptr -= cnt; + } + if((s->top - s->lim) < 512){ + uchar *buf = (uchar*) malloc(((s->lim - s->bot) + 512)*sizeof(uchar)); + memcpy(buf, s->bot, s->lim - s->bot); + s->tok = buf; + s->ptr = &buf[s->ptr - s->bot]; + if(s->eot) + s->eot = &buf[s->eot - s->bot]; + cursor = &buf[cursor - s->bot]; + s->lim = &buf[s->lim - s->bot]; + s->top = &s->lim[512]; + free(s->bot); + s->bot = buf; + } + s->mrk = cursor; + if(ScanCBIO.file){ + if((cnt = read(ScanCBIO.u.f.fd, (char*) s->lim, 512)) != 512) + memset(&s->lim[cnt], 0, 512 - cnt); + s->lim += 512; + } + return cursor; +} diff --git a/examples/sample.re b/examples/sample.re new file mode 100644 index 00000000..2f497a3b --- /dev/null +++ b/examples/sample.re @@ -0,0 +1,7 @@ +/*!re2c + "print" {return PRINT;} + [a-z]+ {return ID;} + [0-9]+ {return DEC;} + "0x" [0-9a-f]+ {return HEX;} + [\000-\377] {return ERR;} +*/ diff --git a/examples/simple.re b/examples/simple.re new file mode 100644 index 00000000..5fd8891f --- /dev/null +++ b/examples/simple.re @@ -0,0 +1,13 @@ +#define NULL ((char*) 0) +char *scan(char *p){ +char *q; +#define YYCTYPE char +#define YYCURSOR p +#define YYLIMIT p +#define YYMARKER q +#define YYFILL(n) +/*!re2c + [0-9]+ {return YYCURSOR;} + [\000-\377] {return NULL;} +*/ +} diff --git a/globals.h b/globals.h new file mode 100644 index 00000000..79edbff9 --- /dev/null +++ b/globals.h @@ -0,0 +1,15 @@ +#ifndef _globals_h +#define _globals_h + +#include "basics.h" + +extern char *fileName; +extern bool sFlag; +extern bool bFlag; + +extern uchar asc2ebc[256]; +extern uchar ebc2asc[256]; + +extern uchar *xlat, *talx; + +#endif diff --git a/ins.h b/ins.h new file mode 100644 index 00000000..5d08cca2 --- /dev/null +++ b/ins.h @@ -0,0 +1,41 @@ +#ifndef _ins_h +#define _ins_h + +#include +#include "basics.h" + +const uint nChars = 256; +typedef uchar Char; + +const uint CHAR = 0; +const uint GOTO = 1; +const uint FORK = 2; +const uint TERM = 3; +const uint CTXT = 4; + +union Ins { + struct { + byte tag; + byte marked; + void *link; + } i; + struct { + ushort value; + ushort bump; + void *link; + } c; +}; + +inline bool isMarked(Ins *i){ + return i->i.marked != 0; +} + +inline void mark(Ins *i){ + i->i.marked = true; +} + +inline void unmark(Ins *i){ + i->i.marked = false; +} + +#endif diff --git a/main.cc b/main.cc new file mode 100644 index 00000000..9e22c23e --- /dev/null +++ b/main.cc @@ -0,0 +1,54 @@ +#include +#include +#include +#include + +#include "globals.h" +#include "parser.h" +#include "dfa.h" + +char *fileName; +bool sFlag = false; +bool bFlag = false; + +int main(unsigned argc, char *argv[]){ + fileName = NULL; + if(argc == 1) + goto usage; + while(--argc > 1){ + char *p = *++argv; + while(*++p != '\0'){ + switch(*p){ + case 'e': + xlat = asc2ebc; + talx = ebc2asc; + break; + case 's': + sFlag = true; + break; + case 'b': + sFlag = true; + bFlag = true; + break; + default: + goto usage; + } + } + } + fileName = *++argv; + int fd; + if(fileName[0] == '-' && fileName[1] == '\0'){ + fileName = ""; + fd = 0; + } else { + if((fd = open(fileName, O_RDONLY)) < 0){ + cerr << "can't open " << fileName << "\n"; + return 1; + } + } + parse(fd, cout); + return 0; +usage: + cerr << "usage: re2c [-esb] name\n"; + return 2; +} diff --git a/parser.cc b/parser.cc new file mode 100644 index 00000000..6d664005 --- /dev/null +++ b/parser.cc @@ -0,0 +1,531 @@ +#ifndef lint +static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; +#endif +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define yyclearin (yychar=(-1)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING (yyerrflag!=0) +#define YYPREFIX "yy" +#line 2 "parser.y" + +#include +#include +#include +#include +#include "globals.h" +#include "parser.h" +int yyparse(); +int yylex(); +void yyerror(char*); + +static uint accept; +static RegExp *spec; +static Scanner *in; + +#line 21 "parser.y" +typedef union { + Symbol *symbol; + RegExp *regexp; + Token *token; + char op; +} YYSTYPE; +#line 35 "y.tab.c" +#define CLOSE 257 +#define ID 258 +#define CODE 259 +#define RANGE 260 +#define STRING 261 +#define YYERRCODE 256 +short yylhs[] = { -1, + 0, 0, 0, 9, 2, 3, 3, 4, 4, 5, + 5, 6, 6, 7, 7, 1, 1, 8, 8, 8, + 8, +}; +short yylen[] = { 2, + 0, 2, 2, 4, 3, 0, 2, 1, 3, 1, + 3, 1, 2, 1, 2, 1, 2, 1, 1, 1, + 3, +}; +short yydefred[] = { 1, + 0, 0, 19, 20, 0, 2, 0, 0, 0, 12, + 0, 3, 0, 18, 0, 0, 0, 0, 0, 13, + 16, 0, 0, 21, 0, 0, 5, 0, 17, 4, +}; +short yydgoto[] = { 1, + 22, 6, 18, 7, 8, 9, 10, 11, 12, +}; +short yysindex[] = { 0, + -27, -49, 0, 0, -23, 0, -44, -84, -23, 0, + -243, 0, -23, 0, -39, -23, -23, -244, -23, 0, + 0, -239, -53, 0, -104, -84, 0, -23, 0, 0, +}; +short yyrindex[] = { 0, + 0, -31, 0, 0, 0, 0, -227, -17, -20, 0, + -40, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -36, 0, 0, -226, -16, 0, -19, 0, 0, +}; +short yygindex[] = { 0, + 0, 0, 0, 21, 18, 17, 1, 0, 0, +}; +#define YYTABLESIZE 243 +short yytable[] = { 14, + 14, 24, 16, 15, 15, 30, 14, 19, 18, 20, + 15, 13, 5, 21, 27, 18, 5, 29, 14, 17, + 10, 11, 15, 8, 9, 15, 10, 11, 20, 8, + 9, 6, 7, 23, 26, 28, 25, 0, 10, 11, + 0, 8, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 14, 0, 0, 0, 15, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 17, 10, 11, 0, 0, 0, 0, 0, 0, 17, + 0, 0, 0, 14, 17, 0, 0, 15, 0, 0, + 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 11, 0, 8, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, + 14, 15, 15, 15, 15, 18, 18, 18, 18, 18, + 2, 0, 3, 4, 14, 0, 3, 4, 10, 11, + 0, 8, 9, +}; +short yycheck[] = { 40, + 41, 41, 47, 40, 41, 59, 47, 92, 40, 9, + 47, 61, 40, 257, 259, 47, 40, 257, 59, 124, + 41, 41, 59, 41, 41, 5, 47, 47, 28, 47, + 47, 259, 259, 13, 17, 19, 16, -1, 59, 59, + -1, 59, 59, -1, -1, -1, -1, -1, -1, -1, + -1, 92, -1, -1, -1, 92, -1, -1, -1, -1, + 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 124, 92, 92, -1, -1, -1, -1, -1, -1, 124, + -1, -1, -1, 124, 124, -1, -1, 124, -1, -1, + -1, -1, 124, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 124, 124, -1, 124, 124, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 258, 259, 260, + 261, 258, 259, 260, 261, 257, 258, 259, 260, 261, + 258, -1, 260, 261, 258, -1, 260, 261, 259, 259, + -1, 259, 259, +}; +#define YYFINAL 1 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 261 +#if YYDEBUG +char *yyname[] = { +"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,"'('","')'",0,0,0,0,0,"'/'",0,0,0,0,0,0,0,0,0,0,0,"';'",0,"'='",0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'\\\\'",0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'|'",0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +"CLOSE","ID","CODE","RANGE","STRING", +}; +char *yyrule[] = { +"$accept : spec", +"spec :", +"spec : spec rule", +"spec : spec decl", +"decl : ID '=' expr ';'", +"rule : expr look CODE", +"look :", +"look : '/' expr", +"expr : diff", +"expr : expr '|' diff", +"diff : term", +"diff : diff '\\\\' term", +"term : factor", +"term : term factor", +"factor : primary", +"factor : primary close", +"close : CLOSE", +"close : close CLOSE", +"primary : ID", +"primary : RANGE", +"primary : STRING", +"primary : '(' expr ')'", +}; +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 500 +#define YYMAXDEPTH 500 +#endif +#endif +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short yyss[YYSTACKSIZE]; +YYSTYPE yyvs[YYSTACKSIZE]; +#define yystacksize YYSTACKSIZE +#line 121 "parser.y" + +void yyerror(char* s){ + in->fatal(s); +} + +int yylex(){ + return in->scan(); +} + +void parse(int i, ostream &o){ + char * fnamebuf; + char * token; + + o << "/* Generated by re2c 0.5 on "; + time_t now = time(&now); + o.write(ctime(&now), 24); + o << " */\n"; + + in = new Scanner(i); + + o << "#line " << in->line() << " \""; + if( fileName != NULL ) { + fnamebuf = strdup( fileName ); + } else { + fnamebuf = strdup( "" ); + } + token = strtok( fnamebuf, "\\" ); + for(;;) { + o << token; + token = strtok( NULL, "\\" ); + if( token == NULL ) break; + o << "\\\\"; + } + o << "\"\n"; + free( fnamebuf ); + + while(in->echo(o)){ + yyparse(); + if(spec) + genCode(o, spec); + o << "#line " << in->line() << "\n"; + } +} +#line 235 "y.tab.c" +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab +int +yyparse() +{ + register int yym, yyn, yystate; +#if YYDEBUG + register char *yys; + extern char *getenv(); + + if (yys = getenv("YYDEBUG")) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if (yyn = yydefred[yystate]) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#ifdef lint + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#ifdef lint + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { +case 1: +#line 40 "parser.y" +{ accept = 0; + spec = NULL; } +break; +case 2: +#line 43 "parser.y" +{ spec = spec? mkAlt(spec, yyvsp[0].regexp) : yyvsp[0].regexp; } +break; +case 4: +#line 48 "parser.y" +{ if(yyvsp[-3].symbol->re) + in->fatal("sym already defined"); + yyvsp[-3].symbol->re = yyvsp[-1].regexp; } +break; +case 5: +#line 54 "parser.y" +{ yyval.regexp = new RuleOp(yyvsp[-2].regexp, yyvsp[-1].regexp, yyvsp[0].token, accept++); } +break; +case 6: +#line 58 "parser.y" +{ yyval.regexp = new NullOp; } +break; +case 7: +#line 60 "parser.y" +{ yyval.regexp = yyvsp[0].regexp; } +break; +case 8: +#line 64 "parser.y" +{ yyval.regexp = yyvsp[0].regexp; } +break; +case 9: +#line 66 "parser.y" +{ yyval.regexp = mkAlt(yyvsp[-2].regexp, yyvsp[0].regexp); } +break; +case 10: +#line 70 "parser.y" +{ yyval.regexp = yyvsp[0].regexp; } +break; +case 11: +#line 72 "parser.y" +{ yyval.regexp = mkDiff(yyvsp[-2].regexp, yyvsp[0].regexp); + if(!yyval.regexp) + in->fatal("can only difference char sets"); + } +break; +case 12: +#line 79 "parser.y" +{ yyval.regexp = yyvsp[0].regexp; } +break; +case 13: +#line 81 "parser.y" +{ yyval.regexp = new CatOp(yyvsp[-1].regexp, yyvsp[0].regexp); } +break; +case 14: +#line 85 "parser.y" +{ yyval.regexp = yyvsp[0].regexp; } +break; +case 15: +#line 87 "parser.y" +{ + switch(yyvsp[0].op){ + case '*': + yyval.regexp = mkAlt(new CloseOp(yyvsp[-1].regexp), new NullOp()); + break; + case '+': + yyval.regexp = new CloseOp(yyvsp[-1].regexp); + break; + case '?': + yyval.regexp = mkAlt(yyvsp[-1].regexp, new NullOp()); + break; + } + } +break; +case 16: +#line 103 "parser.y" +{ yyval.op = yyvsp[0].op; } +break; +case 17: +#line 105 "parser.y" +{ yyval.op = (yyvsp[-1].op == yyvsp[0].op) ? yyvsp[-1].op : '*'; } +break; +case 18: +#line 109 "parser.y" +{ if(!yyvsp[0].symbol->re) + in->fatal("can't find symbol"); + yyval.regexp = yyvsp[0].symbol->re; } +break; +case 19: +#line 113 "parser.y" +{ yyval.regexp = yyvsp[0].regexp; } +break; +case 20: +#line 115 "parser.y" +{ yyval.regexp = yyvsp[0].regexp; } +break; +case 21: +#line 117 "parser.y" +{ yyval.regexp = yyvsp[-1].regexp; } +break; +#line 476 "y.tab.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} diff --git a/parser.h b/parser.h new file mode 100644 index 00000000..56178a80 --- /dev/null +++ b/parser.h @@ -0,0 +1,20 @@ +#ifndef _parser_h +#define _parser_h + +#include "scanner.h" +#include "re.h" + +class Symbol { +public: + static Symbol *first; + Symbol *next; + Str name; + RegExp *re; +public: + Symbol(const SubStr&); + static Symbol *find(const SubStr&); +}; + +void parse(int, ostream&); + +#endif diff --git a/parser.y b/parser.y new file mode 100644 index 00000000..8f2a7dce --- /dev/null +++ b/parser.y @@ -0,0 +1,163 @@ +%{ + +#include +#include +#include +#include +#include "globals.h" +#include "parser.h" +int yyparse(); +int yylex(); +void yyerror(char*); + +static uint accept; +static RegExp *spec; +static Scanner *in; + +%} + +%start spec + +%union { + Symbol *symbol; + RegExp *regexp; + Token *token; + char op; +} + +%token CLOSE ID CODE RANGE STRING + +%type CLOSE +%type close +%type ID +%type CODE +%type RANGE STRING +%type rule look expr diff term factor primary + +%% + +spec : + { accept = 0; + spec = NULL; } + | spec rule + { spec = spec? mkAlt(spec, $2) : $2; } + | spec decl + ; + +decl : ID '=' expr ';' + { if($1->re) + in->fatal("sym already defined"); + $1->re = $3; } + ; + +rule : expr look CODE + { $$ = new RuleOp($1, $2, $3, accept++); } + ; + +look : + { $$ = new NullOp; } + | '/' expr + { $$ = $2; } + ; + +expr : diff + { $$ = $1; } + | expr '|' diff + { $$ = mkAlt($1, $3); } + ; + +diff : term + { $$ = $1; } + | diff '\\' term + { $$ = mkDiff($1, $3); + if(!$$) + in->fatal("can only difference char sets"); + } + ; + +term : factor + { $$ = $1; } + | term factor + { $$ = new CatOp($1, $2); } + ; + +factor : primary + { $$ = $1; } + | primary close + { + switch($2){ + case '*': + $$ = mkAlt(new CloseOp($1), new NullOp()); + break; + case '+': + $$ = new CloseOp($1); + break; + case '?': + $$ = mkAlt($1, new NullOp()); + break; + } + } + ; + +close : CLOSE + { $$ = $1; } + | close CLOSE + { $$ = ($1 == $2) ? $1 : '*'; } + ; + +primary : ID + { if(!$1->re) + in->fatal("can't find symbol"); + $$ = $1->re; } + | RANGE + { $$ = $1; } + | STRING + { $$ = $1; } + | '(' expr ')' + { $$ = $2; } + ; + +%% + +void yyerror(char* s){ + in->fatal(s); +} + +int yylex(){ + return in->scan(); +} + +void parse(int i, ostream &o){ + char * fnamebuf; + char * token; + + o << "/* Generated by re2c 0.5 on "; + time_t now = time(&now); + o.write(ctime(&now), 24); + o << " */\n"; + + in = new Scanner(i); + + o << "#line " << in->line() << " \""; + if( fileName != NULL ) { + fnamebuf = strdup( fileName ); + } else { + fnamebuf = strdup( "" ); + } + token = strtok( fnamebuf, "\\" ); + for(;;) { + o << token; + token = strtok( NULL, "\\" ); + if( token == NULL ) break; + o << "\\\\"; + } + o << "\"\n"; + free( fnamebuf ); + + while(in->echo(o)){ + yyparse(); + if(spec) + genCode(o, spec); + o << "#line " << in->line() << "\n"; + } +} diff --git a/re.h b/re.h new file mode 100644 index 00000000..2ea6e63b --- /dev/null +++ b/re.h @@ -0,0 +1,178 @@ +#ifndef _re_h +#define _re_h + +#include +#include "token.h" +#include "ins.h" + +struct CharPtn { + uint card; + CharPtn *fix; + CharPtn *nxt; +}; + +struct CharSet { + CharPtn *fix; + CharPtn *freeHead, **freeTail; + CharPtn *rep[nChars]; + CharPtn ptn[nChars]; +}; + +class Range { +public: + Range *next; + uint lb, ub; // [lb,ub) +public: + Range(uint l, uint u) : next(NULL), lb(l), ub(u) + { } + Range(Range &r) : next(NULL), lb(r.lb), ub(r.ub) + { } + friend ostream& operator<<(ostream&, const Range&); + friend ostream& operator<<(ostream&, const Range*); +}; + +inline ostream& operator<<(ostream &o, const Range *r){ + return r? o << *r : o; +} + +class RegExp { +public: + uint size; +public: + virtual char *typeOf() = 0; + RegExp *isA(char *t) + { return typeOf() == t? this : NULL; } + virtual void split(CharSet&) = 0; + virtual void calcSize(Char*) = 0; + virtual uint fixedLength(); + virtual void compile(Char*, Ins*) = 0; + virtual void display(ostream&) const = 0; + friend ostream& operator<<(ostream&, const RegExp&); + friend ostream& operator<<(ostream&, const RegExp*); +}; + +inline ostream& operator<<(ostream &o, const RegExp &re){ + re.display(o); + return o; +} + +inline ostream& operator<<(ostream &o, const RegExp *re){ + return o << *re; +} + +class NullOp: public RegExp { +public: + static char *type; +public: + char *typeOf() + { return type; } + void split(CharSet&); + void calcSize(Char*); + uint fixedLength(); + void compile(Char*, Ins*); + void display(ostream &o) const { + o << "_"; + } +}; + +class MatchOp: public RegExp { +public: + static char *type; + Range *match; +public: + MatchOp(Range *m) : match(m) + { } + char *typeOf() + { return type; } + void split(CharSet&); + void calcSize(Char*); + uint fixedLength(); + void compile(Char*, Ins*); + void display(ostream&) const; +}; + +class RuleOp: public RegExp { +private: + RegExp *exp; +public: + RegExp *ctx; + static char *type; + Ins *ins; + uint accept; + Token *code; + uint line; +public: + RuleOp(RegExp*, RegExp*, Token*, uint); + char *typeOf() + { return type; } + void split(CharSet&); + void calcSize(Char*); + void compile(Char*, Ins*); + void display(ostream &o) const { + o << exp << "/" << ctx << ";"; + } +}; + +class AltOp: public RegExp { +private: + RegExp *exp1, *exp2; +public: + static char *type; +public: + AltOp(RegExp *e1, RegExp *e2) + { exp1 = e1; exp2 = e2; } + char *typeOf() + { return type; } + void split(CharSet&); + void calcSize(Char*); + uint fixedLength(); + void compile(Char*, Ins*); + void display(ostream &o) const { + o << exp1 << "|" << exp2; + } + friend RegExp *mkAlt(RegExp*, RegExp*); +}; + +class CatOp: public RegExp { +private: + RegExp *exp1, *exp2; +public: + static char *type; +public: + CatOp(RegExp *e1, RegExp *e2) + { exp1 = e1; exp2 = e2; } + char *typeOf() + { return type; } + void split(CharSet&); + void calcSize(Char*); + uint fixedLength(); + void compile(Char*, Ins*); + void display(ostream &o) const { + o << exp1 << exp2; + } +}; + +class CloseOp: public RegExp { +private: + RegExp *exp; +public: + static char *type; +public: + CloseOp(RegExp *e) + { exp = e; } + char *typeOf() + { return type; } + void split(CharSet&); + void calcSize(Char*); + void compile(Char*, Ins*); + void display(ostream &o) const { + o << exp << "+"; + } +}; + +extern void genCode(ostream&, RegExp*); +extern RegExp *mkDiff(RegExp*, RegExp*); +extern RegExp *strToRE(SubStr); +extern RegExp *ranToRE(SubStr); + +#endif diff --git a/re2c.1 b/re2c.1 new file mode 100644 index 00000000..a2a580c4 --- /dev/null +++ b/re2c.1 @@ -0,0 +1,536 @@ +.ds re \fBre2c\fP +.ds le \fBlex\fP +.ds rx regular expression +.ds lx \fIl\fP-expression +.TH RE2C 1 "8 April 1994" "Version 0.5" +\"$Log$ +\"Revision 1.1 2003/12/13 04:58:20 nuffer +\"Initial revision +\" +\"Revision 1.2 1994/04/16 15:50:32 peter +\"Fix bug in simple example. +\" +\"Revision 1.1 1994/04/08 15:39:09 peter +\"Initial revision +\" +.SH NAME +re2c \- convert regular expressions to C/C++ + +.SH SYNOPSIS +\*(re [\fB-esb\fP] \fIname\fP + +.SH DESCRIPTION +\*(re is a preprocessor that generates C-based recognizers from regular +expressions. +The input to \*(re consists of C/C++ source interleaved with +comments of the form \fC/*!re2c\fP ... \fC*/\fP which contain +scanner specifications. +In the output these comments are replaced with code that, when +executed, will find the next input token and then execute +some user-supplied token-specific code. + +For example, given the following code + +.in +3 +.nf +#define NULL ((char*) 0) +char *scan(char *p){ +char *q; +#define YYCTYPE char +#define YYCURSOR p +#define YYLIMIT p +#define YYMARKER q +#define YYFILL(n) +/*!re2c + [0-9]+ {return YYCURSOR;} + [\\000-\\377] {return NULL;} +*/ +} +.fi +.in -3 + +\*(re will generate + +.in +3 +.nf +/* Generated by re2c on Sat Apr 16 11:40:58 1994 */ +#line 1 "simple.re" +#define NULL ((char*) 0) +char *scan(char *p){ +char *q; +#define YYCTYPE char +#define YYCURSOR p +#define YYLIMIT p +#define YYMARKER q +#define YYFILL(n) +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy0; +yy1: ++YYCURSOR; +yy0: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= '/') goto yy4; + if(yych >= ':') goto yy4; +yy2: yych = *++YYCURSOR; + goto yy7; +yy3: +#line 10 + {return YYCURSOR;} +yy4: yych = *++YYCURSOR; +yy5: +#line 11 + {return NULL;} +yy6: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy7: if(yych <= '/') goto yy3; + if(yych <= '9') goto yy6; + goto yy3; +} +#line 12 + +} +.fi +.in -3 + +.SH OPTIONS +\*(re provides the following options: +.TP +\fB-e\fP +Cross-compile from an ASCII platform to an EBCDIC one. +.TP +\fB-s\fP +Generate nested \fCif\fPs for some \fCswitch\fPes. Many compilers need this +assist to generate better code. +.TP +\fB-b\fP +Implies \fB-s\fP. Use bit vectors as well in the attempt to coax better +code out of the compiler. Most useful for specifications with more than a +few keywords (e.g. for most programming languages). + +.SH "INTERFACE CODE" +Unlike other scanner generators, \*(re does not generate complete scanners: +the user must supply some interface code. +In particular, the user must define the following macros: +.TP +\fCYYCHAR\fP +Type used to hold an input symbol. +Usually \fCchar\fP or \fCunsigned char\fP. +.TP +\fCYYCURSOR\fP +\*(lx of type \fC*YYCHAR\fP that points to the current input symbol. +The generated code advances \fCYYCURSOR\fP as symbols are matched. +On entry, \fCYYCURSOR\fP is assumed to point to the first character of the +current token. On exit, \fCYYCURSOR\fP will point to the first character of +the following token. +.TP +\fCYLIMIT\fP +Expression of type \fC*YYCHAR\fP that marks the end of the buffer +(\fCYLIMIT[-1]\fP is the last character in the buffer). +The generated code repeatedly compares \fCYYCURSOR\fP to \fCYLIMIT\fP +to determine when the buffer needs (re)filling. +.TP +\fCYYMARKER\fP +\*(lx of type \fC*YYCHAR\fP. +The generated code saves backtracking information in \fCYYMARKER\fP. +.TP +\fCYYFILL(\fP\fIn\fP\fC)\fP +The generated code "calls" \fCYYFILL\fP when the buffer needs +(re)filling: at least \fIn\fP additional characters should +be provided. \fCYYFILL\fP should adjust \fCYYCURSOR\fP, \fCYYLIMIT\fP and +\fCYYMARKER\fP as needed. Note that for typical programming languages +\fIn\fP will be the length of the longest keyword plus one. + +.SH "SCANNER SPECIFICATIONS" +Each scanner specification consists of a set of \fIrules\fP and name +definitions. +Rules consist of a regular expression along with a block of C/C++ code that +is to be executed when the associated regular expression is matched. +Name definitions are of the form +``\fIname\fP \fC=\fP \fIregular expression\fP\fC;\fP''. + +.SH "SUMMARY OF RE2C REGULAR EXPRESSIONS" +.TP +\fC"foo"\fP +the literal string \fCfoo\fP. +ANSI-C escape sequences can be used. +.TP +\fC[xyz]\fP +a "character class"; in this case, +the \*(rx matches either an '\fCx\fP', a '\fCy\fP', or a '\fCz\fP'. +.TP +\fC[abj-oZ]\fP +a "character class" with a range in it; +matches an '\fCa\fP', a '\fCb\fP', any letter from '\fCj\fP' through '\fCo\fP', +or a '\fCZ\fP'. +.TP +\fIr\fP\fC\e\fP\fIs\fP +match any \fIr\fP which isn't an \fIs\fP. \fIr\fP and \fIs\fP must be regular expressions +which can be expressed as character classes. +.TP +\fIr\fP\fC*\fP +zero or more \fIr\fP's, where \fIr\fP is any regular expression +.TP +\fC\fIr\fP\fC+\fP +one or more \fIr\fP's +.TP +\fC\fIr\fP\fC?\fP +zero or one \fIr\fP's (that is, "an optional \fIr\fP") +.TP +name +the expansion of the "name" definition (see above) +.TP +\fC(\fP\fIr\fP\fC)\fP +an \fIr\fP; parentheses are used to override precedence +(see below) +.TP +\fIrs\fP +an \fIr\fP followed by an \fIs\fP ("concatenation") +.TP +\fIr\fP\fC|\fP\fIs\fP +either an \fIr\fP or an \fIs\fP +.TP +\fIr\fP\fC/\fP\fIs\fP +an \fIr\fP but only if it is followed by an \fIs\fP. The s is not part of +the matched text. This type of \*(rx is called "trailing context". +.LP +The regular expressions listed above are grouped according to +precedence, from highest precedence at the top to lowest at the bottom. +Those grouped together have equal precedence. + +.SH "A LARGER EXAMPLE" +.LP +.in +3 +.nf +#include +#include +#include +#include + +#define ADDEQ 257 +#define ANDAND 258 +#define ANDEQ 259 +#define ARRAY 260 +#define ASM 261 +#define AUTO 262 +#define BREAK 263 +#define CASE 264 +#define CHAR 265 +#define CONST 266 +#define CONTINUE 267 +#define DECR 268 +#define DEFAULT 269 +#define DEREF 270 +#define DIVEQ 271 +#define DO 272 +#define DOUBLE 273 +#define ELLIPSIS 274 +#define ELSE 275 +#define ENUM 276 +#define EQL 277 +#define EXTERN 278 +#define FCON 279 +#define FLOAT 280 +#define FOR 281 +#define FUNCTION 282 +#define GEQ 283 +#define GOTO 284 +#define ICON 285 +#define ID 286 +#define IF 287 +#define INCR 288 +#define INT 289 +#define LEQ 290 +#define LONG 291 +#define LSHIFT 292 +#define LSHIFTEQ 293 +#define MODEQ 294 +#define MULEQ 295 +#define NEQ 296 +#define OREQ 297 +#define OROR 298 +#define POINTER 299 +#define REGISTER 300 +#define RETURN 301 +#define RSHIFT 302 +#define RSHIFTEQ 303 +#define SCON 304 +#define SHORT 305 +#define SIGNED 306 +#define SIZEOF 307 +#define STATIC 308 +#define STRUCT 309 +#define SUBEQ 310 +#define SWITCH 311 +#define TYPEDEF 312 +#define UNION 313 +#define UNSIGNED 314 +#define VOID 315 +#define VOLATILE 316 +#define WHILE 317 +#define XOREQ 318 +#define EOI 319 + +typedef unsigned int uint; +typedef unsigned char uchar; + +#define BSIZE 8192 + +#define YYCTYPE uchar +#define YYCURSOR cursor +#define YYLIMIT s->lim +#define YYMARKER s->ptr +#define YYFILL(n) {cursor = fill(s, cursor);} + +#define RET(i) {s->cur = cursor; return i;} + +typedef struct Scanner { + int fd; + uchar *bot, *tok, *ptr, *cur, *pos, *lim, *top, *eof; + uint line; +} Scanner; + +uchar *fill(Scanner *s, uchar *cursor){ + if(!s->eof){ + uint cnt = s->tok - s->bot; + if(cnt){ + memcpy(s->bot, s->tok, s->lim - s->tok); + s->tok = s->bot; + s->ptr -= cnt; + cursor -= cnt; + s->pos -= cnt; + s->lim -= cnt; + } + if((s->top - s->lim) < BSIZE){ + uchar *buf = (uchar*) + malloc(((s->lim - s->bot) + BSIZE)*sizeof(uchar)); + memcpy(buf, s->tok, s->lim - s->tok); + s->tok = buf; + s->ptr = &buf[s->ptr - s->bot]; + cursor = &buf[cursor - s->bot]; + s->pos = &buf[s->pos - s->bot]; + s->lim = &buf[s->lim - s->bot]; + s->top = &s->lim[BSIZE]; + free(s->bot); + s->bot = buf; + } + if((cnt = read(s->fd, (char*) s->lim, BSIZE)) != BSIZE){ + s->eof = &s->lim[cnt]; *(s->eof)++ = '\\n'; + } + s->lim += cnt; + } + return cursor; +} + +int scan(Scanner *s){ + uchar *cursor = s->cur; +std: + s->tok = cursor; +/*!re2c +any = [\\000-\\377]; +O = [0-7]; +D = [0-9]; +L = [a-zA-Z_]; +H = [a-fA-F0-9]; +E = [Ee] [+-]? D+; +FS = [fFlL]; +IS = [uUlL]*; +ESC = [\\\\] ([abfnrtv?'"\\\\] | "x" H+ | O+); +*/ + +/*!re2c + "/*" { goto comment; } + + "auto" { RET(AUTO); } + "break" { RET(BREAK); } + "case" { RET(CASE); } + "char" { RET(CHAR); } + "const" { RET(CONST); } + "continue" { RET(CONTINUE); } + "default" { RET(DEFAULT); } + "do" { RET(DO); } + "double" { RET(DOUBLE); } + "else" { RET(ELSE); } + "enum" { RET(ENUM); } + "extern" { RET(EXTERN); } + "float" { RET(FLOAT); } + "for" { RET(FOR); } + "goto" { RET(GOTO); } + "if" { RET(IF); } + "int" { RET(INT); } + "long" { RET(LONG); } + "register" { RET(REGISTER); } + "return" { RET(RETURN); } + "short" { RET(SHORT); } + "signed" { RET(SIGNED); } + "sizeof" { RET(SIZEOF); } + "static" { RET(STATIC); } + "struct" { RET(STRUCT); } + "switch" { RET(SWITCH); } + "typedef" { RET(TYPEDEF); } + "union" { RET(UNION); } + "unsigned" { RET(UNSIGNED); } + "void" { RET(VOID); } + "volatile" { RET(VOLATILE); } + "while" { RET(WHILE); } + + L (L|D)* { RET(ID); } + + ("0" [xX] H+ IS?) | ("0" D+ IS?) | (D+ IS?) | + (['] (ESC|any\\[\\n\\\\'])* [']) + { RET(ICON); } + + (D+ E FS?) | (D* "." D+ E? FS?) | (D+ "." D* E? FS?) + { RET(FCON); } + + (["] (ESC|any\\[\\n\\\\"])* ["]) + { RET(SCON); } + + "..." { RET(ELLIPSIS); } + ">>=" { RET(RSHIFTEQ); } + "<<=" { RET(LSHIFTEQ); } + "+=" { RET(ADDEQ); } + "-=" { RET(SUBEQ); } + "*=" { RET(MULEQ); } + "/=" { RET(DIVEQ); } + "%=" { RET(MODEQ); } + "&=" { RET(ANDEQ); } + "^=" { RET(XOREQ); } + "|=" { RET(OREQ); } + ">>" { RET(RSHIFT); } + "<<" { RET(LSHIFT); } + "++" { RET(INCR); } + "--" { RET(DECR); } + "->" { RET(DEREF); } + "&&" { RET(ANDAND); } + "||" { RET(OROR); } + "<=" { RET(LEQ); } + ">=" { RET(GEQ); } + "==" { RET(EQL); } + "!=" { RET(NEQ); } + ";" { RET(';'); } + "{" { RET('{'); } + "}" { RET('}'); } + "," { RET(','); } + ":" { RET(':'); } + "=" { RET('='); } + "(" { RET('('); } + ")" { RET(')'); } + "[" { RET('['); } + "]" { RET(']'); } + "." { RET('.'); } + "&" { RET('&'); } + "!" { RET('!'); } + "~" { RET('~'); } + "-" { RET('-'); } + "+" { RET('+'); } + "*" { RET('*'); } + "/" { RET('/'); } + "%" { RET('%'); } + "<" { RET('<'); } + ">" { RET('>'); } + "^" { RET('^'); } + "|" { RET('|'); } + "?" { RET('?'); } + + + [ \\t\\v\\f]+ { goto std; } + + "\\n" + { + if(cursor == s->eof) RET(EOI); + s->pos = cursor; s->line++; + goto std; + } + + any + { + printf("unexpected character: %c\\n", *s->tok); + goto std; + } +*/ + +comment: +/*!re2c + "*/" { goto std; } + "\\n" + { + if(cursor == s->eof) RET(EOI); + s->tok = s->pos = cursor; s->line++; + goto comment; + } + any { goto comment; } +*/ +} + +main(){ + Scanner in; + int t; + memset((char*) &in, 0, sizeof(in)); + in.fd = 0; + while((t = scan(&in)) != EOI){ +/* + printf("%d\\t%.*s\\n", t, in.cur - in.tok, in.tok); + printf("%d\\n", t); +*/ + } + close(in.fd); +} +.fi +.in -3 + +.SH "SEE ALSO" +.LP +flex(1), lex(1). + +.SH FEATURES +.LP +\*(re does not provide a default action: +the generated code assumes that the input +will consist of a sequence of tokens. +Typically this can be dealt with by adding a rule such as the one for +unexpected characters in the example above. +.LP +The user must arrange for a sentinel token to appear at the end of input +(and provide a rule for matching it): +\*(re does not provide an \fC<>\fP expression. +If the source is from a null-byte terminated string, a +rule matching a null character will suffice. If the source is from a +file then the approach taken in the example can be used: pad the input with +a newline (or some other character that can't appear within another token); +upon recognizing such a character check to see if it is the sentinel +and act accordingly. +.LP +\*(re does not provide start conditions: use a separate scanner +specification for each start condition (as illustrated in the above example). +.LP +No [^x]. Use difference instead. +.SH BUGS +.LP +Only fixed length trailing context can be handled. +.LP +The maximum value appearing as a parameter \fIn\fP to \fCYYFILL\fP is not +provided to the generated code (this value is needed for constructing +the interface code). +Note that this value is usually relatively small: for +typical programming languages \fIn\fP will be the length of the longest +keyword plus one. +.LP +Difference only works for character sets. +.LP +The \*(re internal algorithms need documentation. + +.SH AUTHOR +.LP +Please send bug reports, fixes and feedback to: +.LP +.nf +Peter Bumbulis +Computer Systems Group +University of Waterloo +Waterloo, Ontario +N2L 3G1 +Internet: peter@csg.uwaterloo.ca +.fi diff --git a/scanner.cc b/scanner.cc new file mode 100644 index 00000000..19b42597 --- /dev/null +++ b/scanner.cc @@ -0,0 +1,470 @@ +/* Generated by re2c 0.5 on Sat May 15 11:35:52 1999 */ +#line 1 "scanner.re" +#include +#include +#include +#include +#include "scanner.h" +#include "parser.h" +#include "y.tab.h" + +extern YYSTYPE yylval; + +#define BSIZE 8192 + +#define YYCTYPE uchar +#define YYCURSOR cursor +#define YYLIMIT lim +#define YYMARKER ptr +#define YYFILL(n) {cursor = fill(cursor);} + +#define RETURN(i) {cur = cursor; return i;} + + +Scanner::Scanner(int i) : in(i), + bot(NULL), tok(NULL), ptr(NULL), cur(NULL), pos(NULL), lim(NULL), + top(NULL), eof(NULL), tchar(0), tline(0), cline(1) { + ; +} + +uchar *Scanner::fill(uchar *cursor){ + if(!eof){ + uint cnt = tok - bot; + if(cnt){ + memcpy(bot, tok, lim - tok); + tok = bot; + ptr -= cnt; + cursor -= cnt; + pos -= cnt; + lim -= cnt; + } + if((top - lim) < BSIZE){ + uchar *buf = new uchar[(lim - bot) + BSIZE]; + memcpy(buf, tok, lim - tok); + tok = buf; + ptr = &buf[ptr - bot]; + cursor = &buf[cursor - bot]; + pos = &buf[pos - bot]; + lim = &buf[lim - bot]; + top = &lim[BSIZE]; + delete [] bot; + bot = buf; + } + if((cnt = read(in, (char*) lim, BSIZE)) != BSIZE){ + eof = &lim[cnt]; *eof++ = '\n'; + } + lim += cnt; + } + return cursor; +} + +#line 68 + + +int Scanner::echo(ostream &out){ + uchar *cursor = cur; + tok = cursor; +echo: +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy0; +yy1: ++YYCURSOR; +yy0: + if((YYLIMIT - YYCURSOR) < 7) YYFILL(7); + yych = *YYCURSOR; + if(yych == '\n') goto yy4; + if(yych != '/') goto yy6; +yy2: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == '*') goto yy7; +yy3: +#line 82 + { goto echo; } +yy4: yych = *++YYCURSOR; +yy5: +#line 78 + { if(cursor == eof) RETURN(0); + out.write(tok, cursor - tok); + tok = pos = cursor; cline++; + goto echo; } +yy6: yych = *++YYCURSOR; + goto yy3; +yy7: yych = *++YYCURSOR; + if(yych == '!') goto yy9; +yy8: YYCURSOR = YYMARKER; + switch(yyaccept){ + case 0: goto yy3; + } +yy9: yych = *++YYCURSOR; + if(yych != 'r') goto yy8; +yy10: yych = *++YYCURSOR; + if(yych != 'e') goto yy8; +yy11: yych = *++YYCURSOR; + if(yych != '2') goto yy8; +yy12: yych = *++YYCURSOR; + if(yych != 'c') goto yy8; +yy13: yych = *++YYCURSOR; +yy14: +#line 75 + { out.write(tok, &cursor[-7] - tok); + tok = cursor; + RETURN(1); } +} +#line 83 + +} + + +int Scanner::scan(){ + uchar *cursor = cur; + uint depth; + +scan: + tchar = cursor - pos; + tline = cline; + tok = cursor; +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy15; +yy16: ++YYCURSOR; +yy15: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= ':'){ + if(yych <= '"'){ + if(yych <= '\n'){ + if(yych <= '\b') goto yy35; + if(yych <= '\t') goto yy31; + goto yy33; + } else { + if(yych == ' ') goto yy31; + if(yych <= '!') goto yy35; + goto yy23; + } + } else { + if(yych <= '*'){ + if(yych <= '\'') goto yy35; + if(yych <= ')') goto yy27; + goto yy21; + } else { + if(yych <= '+') goto yy28; + if(yych == '/') goto yy19; + goto yy35; + } + } + } else { + if(yych <= 'Z'){ + if(yych <= '='){ + if(yych == '<') goto yy35; + goto yy27; + } else { + if(yych == '?') goto yy28; + if(yych <= '@') goto yy35; + goto yy29; + } + } else { + if(yych <= '`'){ + if(yych <= '[') goto yy25; + if(yych <= '\\') goto yy27; + goto yy35; + } else { + if(yych <= 'z') goto yy29; + if(yych <= '{') goto yy17; + if(yych <= '|') goto yy27; + goto yy35; + } + } + } +yy17: yych = *++YYCURSOR; +yy18: +#line 96 + { depth = 1; + goto code; + } +yy19: yych = *++YYCURSOR; + if(yych == '*') goto yy54; +yy20: +#line 115 + { RETURN(*tok); } +yy21: yych = *++YYCURSOR; + if(yych == '/') goto yy52; +yy22: +#line 117 + { yylval.op = *tok; + RETURN(CLOSE); } +yy23: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != '\n') goto yy48; +yy24: +#line 108 + { fatal("bad string"); } +yy25: yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if(yych != '\n') goto yy42; +yy26: +#line 113 + { fatal("bad character constant"); } +yy27: yych = *++YYCURSOR; + goto yy20; +yy28: yych = *++YYCURSOR; + goto yy22; +yy29: yych = *++YYCURSOR; + goto yy40; +yy30: +#line 120 + { cur = cursor; + yylval.symbol = Symbol::find(token()); + return ID; } +yy31: yych = *++YYCURSOR; + goto yy38; +yy32: +#line 124 + { goto scan; } +yy33: yych = *++YYCURSOR; +yy34: +#line 126 + { if(cursor == eof) RETURN(0); + pos = cursor; cline++; + goto scan; + } +yy35: yych = *++YYCURSOR; +yy36: +#line 131 + { cerr << "unexpected character: " << *tok << endl; + goto scan; + } +yy37: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy38: if(yych == '\t') goto yy37; + if(yych == ' ') goto yy37; + goto yy32; +yy39: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy40: if(yych <= '@'){ + if(yych <= '/') goto yy30; + if(yych <= '9') goto yy39; + goto yy30; + } else { + if(yych <= 'Z') goto yy39; + if(yych <= '`') goto yy30; + if(yych <= 'z') goto yy39; + goto yy30; + } +yy41: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy42: if(yych <= '['){ + if(yych != '\n') goto yy41; + } else { + if(yych <= '\\') goto yy44; + if(yych <= ']') goto yy45; + goto yy41; + } +yy43: YYCURSOR = YYMARKER; + switch(yyaccept){ + case 0: goto yy24; + case 1: goto yy26; + } +yy44: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych == '\n') goto yy43; + goto yy41; +yy45: yych = *++YYCURSOR; +yy46: +#line 110 + { cur = cursor; + yylval.regexp = ranToRE(token()); + return RANGE; } +yy47: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy48: if(yych <= '!'){ + if(yych == '\n') goto yy43; + goto yy47; + } else { + if(yych <= '"') goto yy50; + if(yych != '\\') goto yy47; + } +yy49: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych == '\n') goto yy43; + goto yy47; +yy50: yych = *++YYCURSOR; +yy51: +#line 105 + { cur = cursor; + yylval.regexp = strToRE(token()); + return STRING; } +yy52: yych = *++YYCURSOR; +yy53: +#line 102 + { tok = cursor; + RETURN(0); } +yy54: yych = *++YYCURSOR; +yy55: +#line 99 + { depth = 1; + goto comment; } +} +#line 134 + + +code: +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy56; +yy57: ++YYCURSOR; +yy56: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= '&'){ + if(yych <= '\n'){ + if(yych <= '\t') goto yy64; + goto yy62; + } else { + if(yych == '"') goto yy66; + goto yy64; + } + } else { + if(yych <= '{'){ + if(yych <= '\'') goto yy67; + if(yych <= 'z') goto yy64; + goto yy60; + } else { + if(yych != '}') goto yy64; + } + } +yy58: yych = *++YYCURSOR; +yy59: +#line 138 + { if(--depth == 0){ + cur = cursor; + yylval.token = new Token(token(), tline); + return CODE; + } + goto code; } +yy60: yych = *++YYCURSOR; +yy61: +#line 144 + { ++depth; + goto code; } +yy62: yych = *++YYCURSOR; +yy63: +#line 146 + { if(cursor == eof) fatal("missing '}'"); + pos = cursor; cline++; + goto code; + } +yy64: yych = *++YYCURSOR; +yy65: +#line 150 + { goto code; } +yy66: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == '\n') goto yy65; + goto yy73; +yy67: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == '\n') goto yy65; + goto yy69; +yy68: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy69: if(yych <= '&'){ + if(yych != '\n') goto yy68; + } else { + if(yych <= '\'') goto yy64; + if(yych == '\\') goto yy71; + goto yy68; + } +yy70: YYCURSOR = YYMARKER; + switch(yyaccept){ + case 0: goto yy65; + } +yy71: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych == '\n') goto yy70; + goto yy68; +yy72: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy73: if(yych <= '!'){ + if(yych == '\n') goto yy70; + goto yy72; + } else { + if(yych <= '"') goto yy64; + if(yych != '\\') goto yy72; + } +yy74: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if(yych == '\n') goto yy70; + goto yy72; +} +#line 151 + + +comment: +{ + YYCTYPE yych; + unsigned int yyaccept; + goto yy75; +yy76: ++YYCURSOR; +yy75: + if((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if(yych <= ')'){ + if(yych == '\n') goto yy80; + goto yy82; + } else { + if(yych <= '*') goto yy77; + if(yych == '/') goto yy79; + goto yy82; + } +yy77: yych = *++YYCURSOR; + if(yych == '/') goto yy85; +yy78: +#line 165 + { goto comment; } +yy79: yych = *++YYCURSOR; + if(yych == '*') goto yy83; + goto yy78; +yy80: yych = *++YYCURSOR; +yy81: +#line 161 + { if(cursor == eof) RETURN(0); + tok = pos = cursor; cline++; + goto comment; + } +yy82: yych = *++YYCURSOR; + goto yy78; +yy83: yych = *++YYCURSOR; +yy84: +#line 159 + { ++depth; + goto comment; } +yy85: yych = *++YYCURSOR; +yy86: +#line 155 + { if(--depth == 0) + goto scan; + else + goto comment; } +} +#line 166 + +} + +void Scanner::fatal(char *msg){ + cerr << "line " << tline << ", column " << (tchar + 1) << ": " + << msg << endl; + exit(1); +} diff --git a/scanner.h b/scanner.h new file mode 100644 index 00000000..cf5bb1f2 --- /dev/null +++ b/scanner.h @@ -0,0 +1,30 @@ +#ifndef _scanner_h +#define _scanner_h + +#include "token.h" + +class Scanner { + private: + int in; + uchar *bot, *tok, *ptr, *cur, *pos, *lim, *top, *eof; + uint tchar, tline, cline; + private: + uchar *fill(uchar*); + public: + Scanner(int); + int echo(ostream&); + int scan(); + void fatal(char*); + SubStr token(); + uint line(); +}; + +inline SubStr Scanner::token(){ + return SubStr(tok, cur - tok); +} + +inline uint Scanner::line(){ + return cline; +} + +#endif diff --git a/scanner.re b/scanner.re new file mode 100644 index 00000000..f7b48cbb --- /dev/null +++ b/scanner.re @@ -0,0 +1,173 @@ +#include +#include +#include +#include +#include "scanner.h" +#include "parser.h" +#include "y.tab.h" + +extern YYSTYPE yylval; + +#define BSIZE 8192 + +#define YYCTYPE uchar +#define YYCURSOR cursor +#define YYLIMIT lim +#define YYMARKER ptr +#define YYFILL(n) {cursor = fill(cursor);} + +#define RETURN(i) {cur = cursor; return i;} + + +Scanner::Scanner(int i) : in(i), + bot(NULL), tok(NULL), ptr(NULL), cur(NULL), pos(NULL), lim(NULL), + top(NULL), eof(NULL), tchar(0), tline(0), cline(1) { + ; +} + +uchar *Scanner::fill(uchar *cursor){ + if(!eof){ + uint cnt = tok - bot; + if(cnt){ + memcpy(bot, tok, lim - tok); + tok = bot; + ptr -= cnt; + cursor -= cnt; + pos -= cnt; + lim -= cnt; + } + if((top - lim) < BSIZE){ + uchar *buf = new uchar[(lim - bot) + BSIZE]; + memcpy(buf, tok, lim - tok); + tok = buf; + ptr = &buf[ptr - bot]; + cursor = &buf[cursor - bot]; + pos = &buf[pos - bot]; + lim = &buf[lim - bot]; + top = &lim[BSIZE]; + delete [] bot; + bot = buf; + } + if((cnt = read(in, (char*) lim, BSIZE)) != BSIZE){ + eof = &lim[cnt]; *eof++ = '\n'; + } + lim += cnt; + } + return cursor; +} + +/*!re2c +any = [\000-\377]; +dot = any \ [\n]; +esc = dot \ [\\]; +cstring = "[" ((esc \ [\]]) | "\\" dot)* "]" ; +dstring = "\"" ((esc \ ["] ) | "\\" dot)* "\""; +sstring = "'" ((esc \ ['] ) | "\\" dot)* "'" ; +letter = [a-zA-Z]; +digit = [0-9]; +*/ + +int Scanner::echo(ostream &out){ + uchar *cursor = cur; + tok = cursor; +echo: +/*!re2c + "/*!re2c" { out.write(tok, &cursor[-7] - tok); + tok = cursor; + RETURN(1); } + "\n" { if(cursor == eof) RETURN(0); + out.write(tok, cursor - tok); + tok = pos = cursor; cline++; + goto echo; } + any { goto echo; } +*/ +} + + +int Scanner::scan(){ + uchar *cursor = cur; + uint depth; + +scan: + tchar = cursor - pos; + tline = cline; + tok = cursor; +/*!re2c + "{" { depth = 1; + goto code; + } + "/*" { depth = 1; + goto comment; } + + "*/" { tok = cursor; + RETURN(0); } + + dstring { cur = cursor; + yylval.regexp = strToRE(token()); + return STRING; } + "\"" { fatal("bad string"); } + + cstring { cur = cursor; + yylval.regexp = ranToRE(token()); + return RANGE; } + "[" { fatal("bad character constant"); } + + [()|=;/\\] { RETURN(*tok); } + + [*+?] { yylval.op = *tok; + RETURN(CLOSE); } + + letter (letter|digit)* { cur = cursor; + yylval.symbol = Symbol::find(token()); + return ID; } + + [ \t]+ { goto scan; } + + "\n" { if(cursor == eof) RETURN(0); + pos = cursor; cline++; + goto scan; + } + + any { cerr << "unexpected character: " << *tok << endl; + goto scan; + } +*/ + +code: +/*!re2c + "}" { if(--depth == 0){ + cur = cursor; + yylval.token = new Token(token(), tline); + return CODE; + } + goto code; } + "{" { ++depth; + goto code; } + "\n" { if(cursor == eof) fatal("missing '}'"); + pos = cursor; cline++; + goto code; + } + dstring | sstring | any { goto code; } +*/ + +comment: +/*!re2c + "*/" { if(--depth == 0) + goto scan; + else + goto comment; } + "/*" { ++depth; + goto comment; } + "\n" { if(cursor == eof) RETURN(0); + tok = pos = cursor; cline++; + goto comment; + } + any { goto comment; } +*/ +} + +void Scanner::fatal(char *msg){ + cerr << "line " << tline << ", column " << (tchar + 1) << ": " + << msg << endl; + exit(1); +} diff --git a/substr.cc b/substr.cc new file mode 100644 index 00000000..3275660e --- /dev/null +++ b/substr.cc @@ -0,0 +1,30 @@ +#include +#include "substr.h" + +void SubStr::out(ostream& o) const { + o.write(str, len); +} + +bool operator==(const SubStr &s1, const SubStr &s2){ + return (bool) (s1.len == s2.len && memcmp(s1.str, s2.str, s1.len) == 0); +} + +Str::Str(const SubStr& s) : SubStr(new char[s.len], s.len) { + memcpy(str, s.str, s.len); +} + +Str::Str(Str& s) : SubStr(s.str, s.len) { + s.str = NULL; + s.len = 0; +} + +Str::Str() : SubStr((char*) NULL, 0) { + ; +} + + +Str::~Str() { + delete str; + str = (char*)-1; + len = (uint)-1; +} diff --git a/substr.h b/substr.h new file mode 100644 index 00000000..fb5e2cc2 --- /dev/null +++ b/substr.h @@ -0,0 +1,45 @@ +#ifndef _substr_h +#define _substr_h + +#include +#include "basics.h" + +class SubStr { +public: + char *str; + uint len; +public: + friend bool operator==(const SubStr &, const SubStr &); + SubStr(uchar*, uint); + SubStr(char*, uint); + SubStr(const SubStr&); + void out(ostream&) const; +}; + +class Str: public SubStr { +public: + Str(const SubStr&); + Str(Str&); + Str(); + ~Str(); +}; + +inline ostream& operator<<(ostream& o, const SubStr &s){ + s.out(o); + return o; +} + +inline ostream& operator<<(ostream& o, const SubStr* s){ + return o << *s; +} + +inline SubStr::SubStr(uchar *s, uint l) + : str((char*) s), len(l) { } + +inline SubStr::SubStr(char *s, uint l) + : str(s), len(l) { } + +inline SubStr::SubStr(const SubStr &s) + : str(s.str), len(s.len) { } + +#endif diff --git a/token.h b/token.h new file mode 100644 index 00000000..de51eb48 --- /dev/null +++ b/token.h @@ -0,0 +1,18 @@ +#ifndef _token_h +#define _token_h + +#include "substr.h" + +class Token { + public: + Str text; + uint line; + public: + Token(SubStr, uint); +}; + +inline Token::Token(SubStr t, uint l) : text(t), line(l) { + ; +} + +#endif diff --git a/translate.cc b/translate.cc new file mode 100644 index 00000000..2eeaabf0 --- /dev/null +++ b/translate.cc @@ -0,0 +1,61 @@ +#include "globals.h" + +uchar asc2asc[256] = { +0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, +0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, +0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, +0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, +0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, +0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f, +0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, +0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f, +0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, +0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f, +0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf, +0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf, +0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, +0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf, +0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, +0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff +}; + +uchar *xlat = asc2asc; +uchar *talx = asc2asc; + +uchar asc2ebc[256] = { /* Based on ISO 8859/1 and Code Page 37 */ +0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f,0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f, +0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26,0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f, +0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d,0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61, +0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f, +0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6, +0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d, +0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96, +0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07, +0x20,0x21,0x22,0x23,0x24,0x15,0x06,0x17,0x28,0x29,0x2a,0x2b,0x2c,0x09,0x0a,0x1b, +0x30,0x31,0x1a,0x33,0x34,0x35,0x36,0x08,0x38,0x39,0x3a,0x3b,0x04,0x14,0x3e,0xff, +0x41,0xaa,0x4a,0xb1,0x9f,0xb2,0x6a,0xb5,0xbd,0xb4,0x9a,0x8a,0x5f,0xca,0xaf,0xbc, +0x90,0x8f,0xea,0xfa,0xbe,0xa0,0xb6,0xb3,0x9d,0xda,0x9b,0x8b,0xb7,0xb8,0xb9,0xab, +0x64,0x65,0x62,0x66,0x63,0x67,0x9e,0x68,0x74,0x71,0x72,0x73,0x78,0x75,0x76,0x77, +0xac,0x69,0xed,0xee,0xeb,0xef,0xec,0xbf,0x80,0xfd,0xfe,0xfb,0xfc,0xad,0x8e,0x59, +0x44,0x45,0x42,0x46,0x43,0x47,0x9c,0x48,0x54,0x51,0x52,0x53,0x58,0x55,0x56,0x57, +0x8c,0x49,0xcd,0xce,0xcb,0xcf,0xcc,0xe1,0x70,0xdd,0xde,0xdb,0xdc,0x8d,0xae,0xdf +}; + +uchar ebc2asc[256] = { /* Based on ISO 8859/1 and Code Page 37 */ +0x00,0x01,0x02,0x03,0x9c,0x09,0x86,0x7f,0x97,0x8d,0x8e,0x0b,0x0c,0x0d,0x0e,0x0f, +0x10,0x11,0x12,0x13,0x9d,0x85,0x08,0x87,0x18,0x19,0x92,0x8f,0x1c,0x1d,0x1e,0x1f, +0x80,0x81,0x82,0x83,0x84,0x0a,0x17,0x1b,0x88,0x89,0x8a,0x8b,0x8c,0x05,0x06,0x07, +0x90,0x91,0x16,0x93,0x94,0x95,0x96,0x04,0x98,0x99,0x9a,0x9b,0x14,0x15,0x9e,0x1a, +0x20,0xa0,0xe2,0xe4,0xe0,0xe1,0xe3,0xe5,0xe7,0xf1,0xa2,0x2e,0x3c,0x28,0x2b,0x7c, +0x26,0xe9,0xea,0xeb,0xe8,0xed,0xee,0xef,0xec,0xdf,0x21,0x24,0x2a,0x29,0x3b,0xac, +0x2d,0x2f,0xc2,0xc4,0xc0,0xc1,0xc3,0xc5,0xc7,0xd1,0xa6,0x2c,0x25,0x5f,0x3e,0x3f, +0xf8,0xc9,0xca,0xcb,0xc8,0xcd,0xce,0xcf,0xcc,0x60,0x3a,0x23,0x40,0x27,0x3d,0x22, +0xd8,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0xab,0xbb,0xf0,0xfd,0xde,0xb1, +0xb0,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0xaa,0xba,0xe6,0xb8,0xc6,0xa4, +0xb5,0x7e,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0xa1,0xbf,0xd0,0xdd,0xfe,0xae, +0x5e,0xa3,0xa5,0xb7,0xa9,0xa7,0xb6,0xbc,0xbd,0xbe,0x5b,0x5d,0xaf,0xa8,0xb4,0xd7, +0x7b,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0xad,0xf4,0xf6,0xf2,0xf3,0xf5, +0x7d,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xb9,0xfb,0xfc,0xf9,0xfa,0xff, +0x5c,0xf7,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0xb2,0xd4,0xd6,0xd2,0xd3,0xd5, +0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0xb3,0xdb,0xdc,0xd9,0xda,0x9f +}; diff --git a/y.tab.h b/y.tab.h new file mode 100644 index 00000000..d7b3702d --- /dev/null +++ b/y.tab.h @@ -0,0 +1,12 @@ +#define CLOSE 257 +#define ID 258 +#define CODE 259 +#define RANGE 260 +#define STRING 261 +typedef union { + Symbol *symbol; + RegExp *regexp; + Token *token; + char op; +} YYSTYPE; +extern YYSTYPE yylval; -- 2.40.0