blob: 02d5c668ec377a035d0fd45cdc292673d436610c [file] [log] [blame]
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "tools/re2c/globals.h"
#include "tools/re2c/parse.h"
#include "tools/re2c/parser.h"
int yylex(void);
static RegExp *parse_expr(void);
static RegExp *parse_diff(void);
static RegExp *parse_term(void);
static RegExp *parse_factor(void);
static RegExp *parse_primary(void);
static unsigned int accept;
static RegExp *spec;
static Scanner *in;
static int curtok, peektok;
yystype yylval;
static yystype peekval;
#define get_next_token() (curtok = yylex())
static void
get_peek_token(void)
{
yystype temp = yylval; /* structure copy */
if (peektok != NONE)
Scanner_fatal(in, "more than one token of lookahead?");
peektok = yylex();
peekval = yylval; /* structure copy */
yylval = temp;
}
static void
yyparse(void)
{
RegExp *re, *look;
accept = 0;
spec = NULL;
get_next_token();
while (curtok != 0) {
switch (curtok) {
case ID:
get_peek_token();
if (peektok == '=') {
/* ID = expr; */
Symbol *sym = yylval.symbol;
get_next_token(); /* id */
get_next_token(); /* = */
re = parse_expr();
if (curtok != ';')
Scanner_fatal(in, "missing `;' after regexp");
get_next_token(); /* ; */
if (sym->re)
Scanner_fatal(in, "sym already defined");
sym->re = re;
break;
}
/*@fallthrough@*/
default:
/* rule: expr [/ expr] CODE */
re = parse_expr();
if (!re)
Scanner_fatal(in, "expression syntax error");
if (curtok == '/') {
get_next_token(); /* / */
look = parse_expr();
} else
look = RegExp_new_NullOp();
if (curtok != CODE)
Scanner_fatal(in, "missing code after regexp");
re = RegExp_new_RuleOp(re, look, yylval.token, accept++);
get_next_token(); /* CODE */
spec = spec ? mkAlt(spec, re) : re;
}
}
}
static RegExp *
parse_expr(void)
{
RegExp *e, *f;
e = parse_diff();
while (curtok == '|') {
get_next_token(); /* | */
f = parse_diff();
e = mkAlt(e, f);
}
return e;
}
static RegExp *
parse_diff(void)
{
RegExp *e, *f;
e = parse_term();
while (curtok == '\\') {
get_next_token(); /* \ */
f = parse_term();
e = mkDiff(e, f);
if(!e)
Scanner_fatal(in, "can only difference char sets");
}
return e;
}
static RegExp *
parse_term(void)
{
RegExp *e, *f;
e = parse_factor();
while ((f = parse_factor())) {
e = RegExp_new_CatOp(e, f);
}
return e;
}
static RegExp *
parse_factor(void)
{
RegExp *e;
char ch;
e = parse_primary();
while (curtok == CLOSE || curtok == CLOSESIZE) {
switch (curtok) {
case CLOSE:
ch = yylval.op;
while (get_next_token() == CLOSE) {
if (ch != yylval.op)
ch = '*';
}
switch (ch) {
case '*':
e = mkAlt(RegExp_new_CloseOp(e), RegExp_new_NullOp());
break;
case '+':
e = RegExp_new_CloseOp(e);
break;
case '?':
e = mkAlt(e, RegExp_new_NullOp());
break;
}
break;
case CLOSESIZE:
e = RegExp_new_CloseVOp(e, yylval.extop.minsize,
yylval.extop.maxsize);
get_next_token(); /* CLOSESIZE */
break;
default:
Scanner_fatal(in, "parse error");
break;
}
}
return e;
}
static RegExp *
parse_primary(void)
{
RegExp *e;
switch (curtok) {
case ID:
if (!yylval.symbol->re)
Scanner_fatal(in, "can't find symbol");
e = yylval.symbol->re;
get_next_token();
break;
case RANGE:
case STRING:
e = yylval.regexp;
get_next_token();
break;
case '(':
get_next_token();
e = parse_expr();
if (curtok != ')')
Scanner_fatal(in, "missing closing parenthesis");
get_next_token();
break;
default:
return NULL;
}
return e;
}
int
yylex(void)
{
if (peektok != NONE) {
int tok = peektok;
yylval = peekval;
peektok = NONE;
return tok;
}
return Scanner_scan(in);
}
void line_source(FILE *o, unsigned int line)
{
char * fnamebuf;
char * token;
if (iFlag)
return;
fprintf(o, "#line %u \"", line);
if( fileName != NULL ) {
fnamebuf = mystrdup( fileName );
} else {
fnamebuf = mystrdup( "<stdin>" );
}
token = strtok( fnamebuf, "\\" );
for(;;) {
fprintf(o, "%s", token);
token = strtok( NULL, "\\" );
if( token == NULL ) break;
fputs("\\\\", o);
}
fputs("\"\n", o); oline++;
free( fnamebuf );
}
void parse(FILE *i, FILE *o){
time_t now;
time(&now);
peektok = NONE;
fputs("/* Generated by re2c 0.9.1-C on ", o);
fprintf(o, "%-24s", ctime(&now));
fputs(" */\n", o); oline+=2;
in = Scanner_new(i);
line_source(o, Scanner_line(in));
while(Scanner_echo(in, o)){
yyparse();
if(spec)
genCode(o, spec);
line_source(o, Scanner_line(in));
}
}