#header << #include "config.h" #include #include #include "lsys.h" #include "util.h" #define PURIFY(a,b) void parse_file (FILE *file, const string &path, lsys &l) t_err; void parse_file (const string &path, lsys &l) t_err; extern list include_dirs; >> << #include #include #include "DLGLexer.h" list include_dirs; void parse_file (FILE *file, const string &path, lsys &l) t_err { DLGFileInput in (file); DLGLexer scanner (&in); ANTLRTokenBuffer pipe (&scanner); ANTLRCommonToken token; scanner.setToken (&token); Parser parser (&pipe); parser.init (); parser.current_file = path; parser.parse_file (l); } void parse_file (const string &path, lsys &l) t_err { string ipath(path); list::const_iterator i = include_dirs.begin (); FILE *f; while (!(f = fopen (ipath.c_str (), "r"))) { ipath += ".l"; if ((f = fopen (ipath.c_str (), "r"))) break; if (i == include_dirs.end ()) throw error ("unable to find or open file '" + path + "'"); ipath = *i + "/" + path; i++; } struct filebuf { FILE *f; filebuf (FILE * file) : f (file) {}; ~filebuf () { fclose (f); }; } auto_close(f); parse_file (f, ipath, l); } >> #lexclass COMMENT #token "\n" << skip(); newline(); set_endcol(0); >> #token "\*/" << mode(START); skip(); >> #token "~[]" << skip(); >> #lexclass QW_STRING #token Name "\"" << replchar('\0'); mode(START); >> #token "\\\"" << replchar('\"'); more(); >> #token "~[]" << more(); >> #lexclass START #token "/\*" << mode(COMMENT); skip(); >> #token "\"" << skip(); mode(QW_STRING); >> #token "//~[\n]*" << skip(); >> #token "#~[\n]*" << skip(); >> #token "\n" << skip(); newline(); set_endcol(0); >> #token "[\ ]+" << skip(); >> #token "\t" << skip(); _endcol = ((_endcol-1) & ~7) + 8; >> #token Name "[a-zA-Z][a-z0-9_]*" #token Number "[0-9]+{\.[0-9]+}" class Parser { << public: string current_file; protected: void syn(_ANTLRTokenPtr tok, ANTLRChar *egroup, SetWordType *eset, ANTLRTokenType etok, int k); bool istok (_ANTLRTokenPtr tok, const char *s) { return strcmp (tok->getText(), s) == 0; }; file_pos here () { return file_pos (current_file, LT(1)->getLine (), -1); }; >> #lexclass START parse_file[lsys &l] : parse_lsys[l] "@" ; parse_lsys[lsys &l] : ( statement[$l] )+ | ; statement[lsys &l] : << string s; lsys *m = 0; /* calm down gcc */ >> << istok(LT(1), "include") >>? . ( qw_str:Name << ::parse_file ($qw_str->getText(), l); >> | "\(" br_str:Name "\)" << m = new lsys; ::parse_file ($br_str->getText (), *m); l.add_lsys (m); >> ) | << istok(LT(1), "ruleset") >>? . { module_name>[s] } "\(" << m = new lsys; >> parse_lsys[*m] << l.add_lsys (m); >> "\)" | << istok(LT(1), "define") >>? . module_name>[s] expr_any[$l.defines[s]] ";" | << istok(LT(1), "ignore") >>? . ( module_ref>[s] << $l.ignore_module.insert (s); >> )+ ";" | << !istok(LT(1), ")") >>? /* why is this predicate necessary? */ parse_rule[$l] ; parse_rule[lsys &l] : << rule r; r.constraint = module (1); r.iterations.is_expr = 1; r.iterations = module (0); r.iterations.is_expr = 1; >> parse_modvec[r.pre] ( "\<" parse_module[*(module *)&r] | << if (r.pre.size () == 0) throw error ("symbol to be replaced must be a single module, not an empty sequence", LT(1)->getLine ()); else if (r.pre.size () != 1) throw error ("symbol to be replaced must be a single module, not more", r.pre.first ()); else { *(module *)&r = r.pre.first (); r.pre.erase (); } >> ) { "\>" parse_modvec[r.post] } { ":" expr_numeric[r.constraint] } "=>" ( parse_modvec[r.repl] | /* empty */ ) { "," expr_numeric[r.iterations] } ";" << $l.add_rule(r); >> ; parse_modvec[module_vec &v] : << module m; >> ( parse_module[m] << $v.push_back (m); >> )+ ; parse_module[module &m] : << module v; m.erase (); >> module_head[$m] { "\(" expr_any[v] << $m.push_back (v); v.erase (); >> ( "," expr_any[v] << $m.push_back (v); v.erase (); >> )* "\)" } ; module_head[module &m] : n:Number << $m = module (atof ($n->getText ())); $m.where = here (); >> | module_ref>[$m.str] << $m.is_num = 0; $m.where = here (); >> ; module_name>[string s] : a:Name << $s = $a->getText(); >> ; module_ref>[string s] : module_name>[$s] | "\\" << $s = "\\"; >> | "\+" << $s = "+"; >> | "\-" << $s = "-"; >> | "\*" << $s = "*"; >> | "\/" << $s = "/"; >> | "\^" << $s = "^"; >> | "\{" << $s = "{"; >> | "\}" << $s = "}"; >> | "\." << $s = "."; >> | "\|" << $s = "|"; >> | "\~" << $s = "~"; >> | "\[" << $s = "["; >> | "\]" << $s = "]"; >> | "\!" << $s = "!"; >> | "\&" << $s = "&"; >> | "\%" << $s = "%"; >> ; expr_any[module &v] : expr_numeric[$v] | expr_modvec[$v] ; expr_modvec[module &v] : "\"" parse_modvec[$v] << $v.str.erase (); $v.is_expr = 0; >> "\"" | "\'" parse_modvec[$v] << $v.str.erase (); $v.is_expr = 0; >> ; expr_numeric[module &v] : expr_0[$v] << $v.is_expr = 1; >> ; expr_0[module &v] : << module r; >> expr_1[$v] ( "\&\&" expr_2[r] << $v = module ("&&", $v, r); >> | "\|\|" expr_2[r] << $v = module ("||", $v, r); >> )* | "\!" expr_1[r] << $v = module ("!", r); >> ; expr_1[module &v] : << module r; >> expr_2[$v] { "\>" expr_2[r] << $v = module (">" , $v, r); >> | ">=" expr_2[r] << $v = module (">=", $v, r); >> | "==" expr_2[r] << $v = module ("==", $v, r); >> | "=" expr_2[r] << $v = module ("==", $v, r); >> | "!=" expr_2[r] << $v = module ("!=", $v, r); >> | "\<" expr_2[r] << $v = module ("<" , $v, r); >> | "<=" expr_2[r] << $v = module ("<=", $v, r); >> } ; expr_2[module &v] : << module r; >> << $v = module (0); >> {expr_3[$v]} ( "\+" expr_3[r] << $v = module ("+", $v, r); >> | "\-" expr_3[r] << $v = module ("-", $v, r); >> )* ; expr_3[module &v] : << module r; >> expr_4[$v] ( "\*" expr_4[r] << $v = module ("*", $v, r); >> | "\/" expr_4[r] << $v = module ("/", $v, r); >> | "\%" expr_4[r] << $v = module ("%", $v ,r); >> )* ; expr_4[module &v] : << module r; >> expr_5[$v] ( "\^" expr_5[r] << $v = module ("^", $v, r); >> )* ; expr_5[module &v] : "\(" expr_0[$v] << $v.where = here (); >> "\)" | expr_atom[$v] ; expr_atom[module &v] : num:Number << $v = module (atof ($num->getText ())); $v.where = here (); >> | expr_module[$v] ; expr_module[module &m] : << module v; m.erase (); m.where = here (); >> module_name>[$m.str] { "\(" expr_any[v] << $m.push_back (v); v.erase (); >> ( "," expr_any[v] << $m.push_back (v); v.erase (); >> )* "\)" } ; } << void Parser::syn (_ANTLRTokenPtr tok, ANTLRChar * egroup, SetWordType * eset, ANTLRTokenType etok, int k) { ostringstream msg; syntaxErrCount++; msg << current_file << ":" << LT (1)->getLine () << ": syntax error at \"" << LT (1)->getText (); if (etok || eset) { if (k == 1) msg << " missing"; else { msg << "; \"" << LT (1)->getText () << "\" not"; if (set_deg (eset) > 1) msg << " in"; } if (set_deg (eset) > 0) { SetWordType *p = eset; SetWordType *endp = &(p[bsetsize]); unsigned e = 0; if (set_deg (eset) > 1) msg << " {"; do { register SetWordType t = *p; register SetWordType *b = &(bitmask[0]); do { if (t & *b) msg << " " << token_tbl[e]; e++; } while (++b < &(bitmask[sizeof (SetWordType) * 8])); } while (++p < endp); if (set_deg (eset) > 1) msg << " }"; } else msg << " " << token_tbl[etok]; if (strlen (egroup) > 0) msg << " in " << egroup; msg << endl; throw error (msg.str ()); } } >>