mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-14 20:00:49 +00:00
8c95516224
- updaterevision for automated revision string generation - re2c as a prerequisite to use sc_man in the future - zipdir to automatically generate an engine resource file.
775 lines
14 KiB
Text
775 lines
14 KiB
Text
%{
|
|
|
|
#include "src/util/c99_stdint.h"
|
|
#include <assert.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <limits>
|
|
#include <list>
|
|
#include <map>
|
|
#include <set>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "src/codegen/output.h"
|
|
#include "src/conf/opt.h"
|
|
#include "src/globals.h"
|
|
#include "src/ir/compile.h"
|
|
#include "src/ir/adfa/adfa.h"
|
|
#include "src/ir/regexp/encoding/enc.h"
|
|
#include "src/ir/regexp/encoding/range_suffix.h"
|
|
#include "src/ir/regexp/regexp.h"
|
|
#include "src/ir/regexp/regexp_cat.h"
|
|
#include "src/ir/regexp/regexp_close.h"
|
|
#include "src/ir/regexp/regexp_null.h"
|
|
#include "src/ir/regexp/regexp_rule.h"
|
|
#include "src/ir/rule_rank.h"
|
|
#include "src/ir/skeleton/skeleton.h"
|
|
#include "src/parse/code.h"
|
|
#include "src/parse/extop.h"
|
|
#include "src/parse/loc.h"
|
|
#include "src/parse/parser.h"
|
|
#include "src/parse/scanner.h"
|
|
#include "src/parse/spec.h"
|
|
#include "src/util/counter.h"
|
|
#include "src/util/free_list.h"
|
|
#include "src/util/range.h"
|
|
#include "src/util/smart_ptr.h"
|
|
|
|
#define YYMALLOC malloc
|
|
#define YYFREE free
|
|
|
|
using namespace re2c;
|
|
|
|
extern "C"
|
|
{
|
|
int yylex();
|
|
void yyerror(const char*);
|
|
}
|
|
|
|
static counter_t<rule_rank_t> rank_counter;
|
|
static std::vector<std::string> condnames;
|
|
static re2c::SpecMap specMap;
|
|
static Spec spec;
|
|
static RuleOp *specNone = NULL;
|
|
static RuleOpList specStar;
|
|
static RuleOp * star_default = NULL;
|
|
static Scanner *in = NULL;
|
|
static Scanner::ParseMode parseMode;
|
|
static SetupMap ruleSetupMap;
|
|
static bool foundRules;
|
|
static symbol_table_t symbol_table;
|
|
|
|
/* Bison version 1.875 emits a definition that is not working
|
|
* with several g++ version. Hence we disable it here.
|
|
*/
|
|
#if defined(__GNUC__)
|
|
#define __attribute__(x)
|
|
#endif
|
|
|
|
void context_check(CondList *clist)
|
|
{
|
|
if (!opts->cFlag)
|
|
{
|
|
delete clist;
|
|
in->fatal("conditions are only allowed when using -c switch");
|
|
}
|
|
}
|
|
|
|
void context_none(CondList *clist)
|
|
{
|
|
delete clist;
|
|
context_check(NULL);
|
|
in->fatal("no expression specified");
|
|
}
|
|
|
|
void context_rule
|
|
( CondList * clist
|
|
, const Loc & loc
|
|
, RegExp * expr
|
|
, RegExp * look
|
|
, const Code * code
|
|
, const std::string * newcond
|
|
)
|
|
{
|
|
context_check(clist);
|
|
for(CondList::const_iterator it = clist->begin(); it != clist->end(); ++it)
|
|
{
|
|
if (specMap.find(*it) == specMap.end())
|
|
{
|
|
condnames.push_back (*it);
|
|
}
|
|
|
|
RuleOp * rule = new RuleOp
|
|
( loc
|
|
, expr
|
|
, look
|
|
, rank_counter.next ()
|
|
, code
|
|
, newcond
|
|
);
|
|
specMap[*it].add (rule);
|
|
}
|
|
delete clist;
|
|
delete newcond;
|
|
}
|
|
|
|
void setup_rule(CondList *clist, const Code * code)
|
|
{
|
|
assert(clist);
|
|
assert(code);
|
|
context_check(clist);
|
|
for(CondList::const_iterator it = clist->begin(); it != clist->end(); ++it)
|
|
{
|
|
if (ruleSetupMap.find(*it) != ruleSetupMap.end())
|
|
{
|
|
in->fatalf_at(code->loc.line, "code to setup rule '%s' is already defined", it->c_str());
|
|
}
|
|
ruleSetupMap[*it] = std::make_pair(code->loc.line, code->text);
|
|
}
|
|
delete clist;
|
|
}
|
|
|
|
void default_rule(CondList *clist, const Code * code)
|
|
{
|
|
assert(clist);
|
|
assert(code);
|
|
context_check(clist);
|
|
for(CondList::const_iterator it = clist->begin(); it != clist->end(); ++it)
|
|
{
|
|
RuleOp * def = new RuleOp
|
|
( code->loc
|
|
, in->mkDefault ()
|
|
, new NullOp
|
|
, rule_rank_t::def ()
|
|
, code
|
|
, NULL
|
|
);
|
|
if (!specMap[*it].add_def (def))
|
|
{
|
|
in->fatalf_at(code->loc.line, "code to default rule '%s' is already defined", it->c_str());
|
|
}
|
|
}
|
|
delete clist;
|
|
}
|
|
|
|
%}
|
|
|
|
%start spec
|
|
|
|
%union {
|
|
re2c::RegExp * regexp;
|
|
const re2c::Code * code;
|
|
char op;
|
|
re2c::ExtOp extop;
|
|
std::string * str;
|
|
re2c::CondList * clist;
|
|
};
|
|
|
|
%token TOKEN_CLOSE
|
|
%token TOKEN_CLOSESIZE
|
|
%token TOKEN_CODE
|
|
%token TOKEN_CONF
|
|
%token TOKEN_ID
|
|
%token TOKEN_FID
|
|
%token TOKEN_FID_END
|
|
%token TOKEN_NOCOND
|
|
%token TOKEN_REGEXP
|
|
%token TOKEN_SETUP
|
|
%token TOKEN_STAR
|
|
|
|
%type <op> TOKEN_CLOSE TOKEN_STAR TOKEN_SETUP close
|
|
%type <extop> TOKEN_CLOSESIZE
|
|
%type <code> TOKEN_CODE
|
|
%type <regexp> TOKEN_REGEXP rule look expr diff term factor primary
|
|
%type <str> TOKEN_ID TOKEN_FID newcond
|
|
%type <clist> cond clist
|
|
|
|
%%
|
|
|
|
spec:
|
|
/* empty */
|
|
{
|
|
}
|
|
| spec rule
|
|
{
|
|
foundRules = true;
|
|
}
|
|
| spec decl
|
|
;
|
|
|
|
decl:
|
|
TOKEN_ID '=' expr ';'
|
|
{
|
|
if (!symbol_table.insert (std::make_pair (* $1, $3)).second)
|
|
{
|
|
in->fatal("sym already defined");
|
|
}
|
|
delete $1;
|
|
}
|
|
| TOKEN_FID expr TOKEN_FID_END
|
|
{
|
|
if (!symbol_table.insert (std::make_pair (* $1, $2)).second)
|
|
{
|
|
in->fatal("sym already defined");
|
|
}
|
|
delete $1;
|
|
}
|
|
| TOKEN_ID '=' expr '/'
|
|
{
|
|
in->fatal("trailing contexts are not allowed in named definitions");
|
|
}
|
|
| TOKEN_FID expr '/'
|
|
{
|
|
in->fatal("trailing contexts are not allowed in named definitions");
|
|
}
|
|
| TOKEN_CONF {}
|
|
;
|
|
|
|
rule:
|
|
expr look TOKEN_CODE
|
|
{
|
|
if (opts->cFlag)
|
|
{
|
|
in->fatal("condition or '<*>' required when using -c switch");
|
|
}
|
|
RuleOp * rule = new RuleOp
|
|
( $3->loc
|
|
, $1
|
|
, $2
|
|
, rank_counter.next ()
|
|
, $3
|
|
, NULL
|
|
);
|
|
spec.add (rule);
|
|
}
|
|
| TOKEN_STAR TOKEN_CODE /* default rule */
|
|
{
|
|
if (opts->cFlag)
|
|
in->fatal("condition or '<*>' required when using -c switch");
|
|
RuleOp * def = new RuleOp
|
|
( $2->loc
|
|
, in->mkDefault ()
|
|
, new NullOp
|
|
, rule_rank_t::def ()
|
|
, $2
|
|
, NULL
|
|
);
|
|
if (!spec.add_def (def))
|
|
{
|
|
in->fatal("code to default rule is already defined");
|
|
}
|
|
}
|
|
| '<' cond '>' expr look newcond TOKEN_CODE
|
|
{
|
|
context_rule ($2, $7->loc, $4, $5, $7, $6);
|
|
}
|
|
| '<' cond '>' expr look ':' newcond
|
|
{
|
|
assert($7);
|
|
Loc loc (in->get_fname (), in->get_cline ());
|
|
context_rule ($2, loc, $4, $5, NULL, $7);
|
|
}
|
|
| '<' cond '>' look newcond TOKEN_CODE
|
|
{
|
|
context_none($2);
|
|
delete $5;
|
|
}
|
|
| '<' cond '>' look ':' newcond
|
|
{
|
|
assert($6);
|
|
context_none($2);
|
|
delete $6;
|
|
}
|
|
| '<' cond '>' TOKEN_STAR TOKEN_CODE /* default rule for conditions */
|
|
{
|
|
default_rule($2, $5);
|
|
}
|
|
| '<' TOKEN_STAR '>' expr look newcond TOKEN_CODE
|
|
{
|
|
context_check(NULL);
|
|
RuleOp * rule = new RuleOp
|
|
( $7->loc
|
|
, $4
|
|
, $5
|
|
, rank_counter.next ()
|
|
, $7
|
|
, $6
|
|
);
|
|
specStar.push_back (rule);
|
|
delete $6;
|
|
}
|
|
| '<' TOKEN_STAR '>' expr look ':' newcond
|
|
{
|
|
assert($7);
|
|
context_check(NULL);
|
|
Loc loc (in->get_fname (), in->get_cline ());
|
|
RuleOp * rule = new RuleOp
|
|
( loc
|
|
, $4
|
|
, $5
|
|
, rank_counter.next ()
|
|
, NULL
|
|
, $7
|
|
);
|
|
specStar.push_back (rule);
|
|
delete $7;
|
|
}
|
|
| '<' TOKEN_STAR '>' look newcond TOKEN_CODE
|
|
{
|
|
context_none(NULL);
|
|
delete $5;
|
|
}
|
|
| '<' TOKEN_STAR '>' look ':' newcond
|
|
{
|
|
assert($6);
|
|
context_none(NULL);
|
|
delete $6;
|
|
}
|
|
| '<' TOKEN_STAR '>' TOKEN_STAR TOKEN_CODE /* default rule for all conditions */
|
|
{
|
|
if (star_default)
|
|
{
|
|
in->fatal ("code to default rule '*' is already defined");
|
|
}
|
|
star_default = new RuleOp
|
|
( $5->loc
|
|
, in->mkDefault ()
|
|
, new NullOp
|
|
, rule_rank_t::def ()
|
|
, $5
|
|
, NULL
|
|
);
|
|
}
|
|
| TOKEN_NOCOND newcond TOKEN_CODE
|
|
{
|
|
context_check(NULL);
|
|
if (specNone)
|
|
{
|
|
in->fatal("code to handle illegal condition already defined");
|
|
}
|
|
$$ = specNone = new RuleOp
|
|
( $3->loc
|
|
, new NullOp
|
|
, new NullOp
|
|
, rank_counter.next ()
|
|
, $3
|
|
, $2
|
|
);
|
|
delete $2;
|
|
}
|
|
| TOKEN_NOCOND ':' newcond
|
|
{
|
|
assert($3);
|
|
context_check(NULL);
|
|
if (specNone)
|
|
{
|
|
in->fatal("code to handle illegal condition already defined");
|
|
}
|
|
Loc loc (in->get_fname (), in->get_cline ());
|
|
$$ = specNone = new RuleOp
|
|
( loc
|
|
, new NullOp
|
|
, new NullOp
|
|
, rank_counter.next ()
|
|
, NULL
|
|
, $3
|
|
);
|
|
delete $3;
|
|
}
|
|
| TOKEN_SETUP TOKEN_STAR '>' TOKEN_CODE
|
|
{
|
|
CondList *clist = new CondList();
|
|
clist->insert("*");
|
|
setup_rule(clist, $4);
|
|
}
|
|
| TOKEN_SETUP cond '>' TOKEN_CODE
|
|
{
|
|
setup_rule($2, $4);
|
|
}
|
|
;
|
|
|
|
cond:
|
|
/* empty */
|
|
{
|
|
in->fatal("unnamed condition not supported");
|
|
}
|
|
| clist
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
clist:
|
|
TOKEN_ID
|
|
{
|
|
$$ = new CondList();
|
|
$$->insert(* $1);
|
|
delete $1;
|
|
}
|
|
| clist ',' TOKEN_ID
|
|
{
|
|
$1->insert(* $3);
|
|
delete $3;
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
newcond:
|
|
/* empty */
|
|
{
|
|
$$ = NULL;
|
|
}
|
|
| '=' '>' TOKEN_ID
|
|
{
|
|
$$ = $3;
|
|
}
|
|
;
|
|
|
|
look:
|
|
/* empty */
|
|
{
|
|
$$ = new NullOp;
|
|
}
|
|
| '/' expr
|
|
{
|
|
$$ = $2;
|
|
}
|
|
;
|
|
|
|
expr:
|
|
diff
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| expr '|' diff
|
|
{
|
|
$$ = mkAlt($1, $3);
|
|
}
|
|
;
|
|
|
|
diff:
|
|
term
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| diff '\\' term
|
|
{
|
|
$$ = in->mkDiff($1, $3);
|
|
}
|
|
;
|
|
|
|
term:
|
|
factor
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| term factor
|
|
{
|
|
$$ = new CatOp($1, $2);
|
|
}
|
|
;
|
|
|
|
factor:
|
|
primary
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| primary close
|
|
{
|
|
switch($2)
|
|
{
|
|
case '*':
|
|
$$ = new CloseOp($1);
|
|
break;
|
|
case '+':
|
|
$$ = new CatOp (new CloseOp($1), $1);
|
|
break;
|
|
case '?':
|
|
$$ = mkAlt($1, new NullOp());
|
|
break;
|
|
}
|
|
}
|
|
| primary TOKEN_CLOSESIZE
|
|
{
|
|
if ($2.max == std::numeric_limits<uint32_t>::max())
|
|
{
|
|
$$ = repeat_from ($1, $2.min);
|
|
}
|
|
else if ($2.min == $2.max)
|
|
{
|
|
$$ = repeat ($1, $2.min);
|
|
}
|
|
else
|
|
{
|
|
$$ = repeat_from_to ($1, $2.min, $2.max);
|
|
}
|
|
$$ = $$ ? $$ : new NullOp;
|
|
}
|
|
;
|
|
|
|
close:
|
|
TOKEN_CLOSE
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| TOKEN_STAR
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| close TOKEN_CLOSE
|
|
{
|
|
$$ = ($1 == $2) ? $1 : '*';
|
|
}
|
|
| close TOKEN_STAR
|
|
{
|
|
$$ = ($1 == $2) ? $1 : '*';
|
|
}
|
|
;
|
|
|
|
primary:
|
|
TOKEN_ID
|
|
{
|
|
symbol_table_t::iterator i = symbol_table.find (* $1);
|
|
delete $1;
|
|
if (i == symbol_table.end ())
|
|
{
|
|
in->fatal("can't find symbol");
|
|
}
|
|
$$ = i->second;
|
|
}
|
|
| TOKEN_REGEXP
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| '(' expr ')'
|
|
{
|
|
$$ = $2;
|
|
}
|
|
;
|
|
|
|
%%
|
|
|
|
extern "C" {
|
|
void yyerror(const char* s)
|
|
{
|
|
in->fatal(s);
|
|
}
|
|
|
|
int yylex(){
|
|
return in ? in->scan() : 0;
|
|
}
|
|
} // end extern "C"
|
|
|
|
namespace re2c
|
|
{
|
|
|
|
void parse(Scanner& i, Output & o)
|
|
{
|
|
std::map<std::string, smart_ptr<DFA> > dfa_map;
|
|
ScannerState rules_state;
|
|
|
|
in = &i;
|
|
|
|
o.source.wversion_time ()
|
|
.wline_info (in->get_cline (), in->get_fname ().c_str ());
|
|
if (opts->target == opt_t::SKELETON)
|
|
{
|
|
Skeleton::emit_prolog (o.source);
|
|
}
|
|
|
|
Enc encodingOld = opts->encoding;
|
|
|
|
while ((parseMode = i.echo()) != Scanner::Stop)
|
|
{
|
|
o.source.new_block ();
|
|
bool bPrologBrace = false;
|
|
ScannerState curr_state;
|
|
|
|
i.save_state(curr_state);
|
|
foundRules = false;
|
|
|
|
if (opts->rFlag && parseMode == Scanner::Rules && dfa_map.size())
|
|
{
|
|
in->fatal("cannot have a second 'rules:re2c' block");
|
|
}
|
|
if (parseMode == Scanner::Reuse)
|
|
{
|
|
if (dfa_map.empty())
|
|
{
|
|
in->fatal("got 'use:re2c' without 'rules:re2c'");
|
|
}
|
|
}
|
|
else if (parseMode == Scanner::Rules)
|
|
{
|
|
i.save_state(rules_state);
|
|
}
|
|
else
|
|
{
|
|
dfa_map.clear();
|
|
}
|
|
rank_counter.reset ();
|
|
spec.clear ();
|
|
in->set_in_parse(true);
|
|
yyparse();
|
|
in->set_in_parse(false);
|
|
if (opts->rFlag && parseMode == Scanner::Reuse)
|
|
{
|
|
if (foundRules || opts->encoding != encodingOld)
|
|
{
|
|
// Re-parse rules
|
|
parseMode = Scanner::Parse;
|
|
i.restore_state(rules_state);
|
|
i.reuse();
|
|
dfa_map.clear();
|
|
parse_cleanup();
|
|
spec.clear ();
|
|
rank_counter.reset ();
|
|
in->set_in_parse(true);
|
|
yyparse();
|
|
in->set_in_parse(false);
|
|
|
|
// Now append potential new rules
|
|
i.restore_state(curr_state);
|
|
parseMode = Scanner::Parse;
|
|
in->set_in_parse(true);
|
|
yyparse();
|
|
in->set_in_parse(false);
|
|
}
|
|
encodingOld = opts->encoding;
|
|
}
|
|
o.source.set_block_line (in->get_cline ());
|
|
uint32_t ind = opts->topIndent;
|
|
if (opts->cFlag)
|
|
{
|
|
SpecMap::iterator it;
|
|
SetupMap::const_iterator itRuleSetup;
|
|
|
|
if (parseMode != Scanner::Reuse)
|
|
{
|
|
// <*> rules must have the lowest priority
|
|
// now that all rules have been parsed, we can fix it
|
|
for (RuleOpList::const_iterator itOp = specStar.begin(); itOp != specStar.end(); ++itOp)
|
|
{
|
|
(*itOp)->rank = rank_counter.next ();
|
|
}
|
|
// merge <*> rules to all conditions
|
|
for (it = specMap.begin(); it != specMap.end(); ++it)
|
|
{
|
|
for (RuleOpList::const_iterator itOp = specStar.begin(); itOp != specStar.end(); ++itOp)
|
|
{
|
|
it->second.add (*itOp);
|
|
}
|
|
if (star_default)
|
|
{
|
|
it->second.add_def (star_default);
|
|
}
|
|
}
|
|
|
|
if (specNone)
|
|
{
|
|
specMap["0"].add (specNone);
|
|
// Note that "0" inserts first, which is important.
|
|
condnames.insert (condnames.begin (), "0");
|
|
}
|
|
o.types = condnames;
|
|
}
|
|
|
|
size_t nCount = specMap.size();
|
|
|
|
for (it = specMap.begin(); it != specMap.end(); ++it)
|
|
{
|
|
if (parseMode != Scanner::Reuse)
|
|
{
|
|
itRuleSetup = ruleSetupMap.find(it->first);
|
|
if (itRuleSetup != ruleSetupMap.end())
|
|
{
|
|
yySetupRule = itRuleSetup->second.second;
|
|
}
|
|
else
|
|
{
|
|
itRuleSetup = ruleSetupMap.find("*");
|
|
if (itRuleSetup != ruleSetupMap.end())
|
|
{
|
|
yySetupRule = itRuleSetup->second.second;
|
|
}
|
|
else
|
|
{
|
|
yySetupRule = "";
|
|
}
|
|
}
|
|
|
|
dfa_map[it->first] = compile(it->second, o, it->first, opts->encoding.nCodeUnits ());
|
|
}
|
|
if (parseMode != Scanner::Rules && dfa_map.find(it->first) != dfa_map.end())
|
|
{
|
|
dfa_map[it->first]->emit(o, ind, !--nCount, bPrologBrace);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (spec.re || !dfa_map.empty())
|
|
{
|
|
if (parseMode != Scanner::Reuse)
|
|
{
|
|
dfa_map[""] = compile(spec, o, "", opts->encoding.nCodeUnits ());
|
|
}
|
|
if (parseMode != Scanner::Rules && dfa_map.find("") != dfa_map.end())
|
|
{
|
|
dfa_map[""]->emit(o, ind, 0, bPrologBrace);
|
|
}
|
|
}
|
|
}
|
|
o.source.wline_info (in->get_cline (), in->get_fname ().c_str ());
|
|
/* restore original char handling mode*/
|
|
opts.reset_encoding (encodingOld);
|
|
}
|
|
|
|
if (opts->cFlag)
|
|
{
|
|
SetupMap::const_iterator itRuleSetup;
|
|
for (itRuleSetup = ruleSetupMap.begin(); itRuleSetup != ruleSetupMap.end(); ++itRuleSetup)
|
|
{
|
|
if (itRuleSetup->first != "*" && specMap.find(itRuleSetup->first) == specMap.end())
|
|
{
|
|
in->fatalf_at(itRuleSetup->second.first, "setup for non existing rule '%s' found", itRuleSetup->first.c_str());
|
|
}
|
|
}
|
|
if (specMap.size() < ruleSetupMap.size())
|
|
{
|
|
uint32_t line = in->get_cline();
|
|
itRuleSetup = ruleSetupMap.find("*");
|
|
if (itRuleSetup != ruleSetupMap.end())
|
|
{
|
|
line = itRuleSetup->second.first;
|
|
}
|
|
in->fatalf_at(line, "setup for all rules with '*' not possible when all rules are setup explicitly");
|
|
}
|
|
}
|
|
|
|
if (opts->target == opt_t::SKELETON)
|
|
{
|
|
Skeleton::emit_epilog (o.source, o.skeletons);
|
|
}
|
|
|
|
parse_cleanup();
|
|
in = NULL;
|
|
}
|
|
|
|
void parse_cleanup()
|
|
{
|
|
RegExp::vFreeList.clear();
|
|
Range::vFreeList.clear();
|
|
RangeSuffix::freeList.clear();
|
|
Code::freelist.clear();
|
|
symbol_table.clear ();
|
|
condnames.clear ();
|
|
specMap.clear();
|
|
specStar.clear();
|
|
star_default = NULL;
|
|
specNone = NULL;
|
|
}
|
|
|
|
} // end namespace re2c
|