📄 process.cpp
字号:
cout << "Reference to undefined nonterminal '" << expr_in.symbol->text << "' at ";
print_terminal_location(cout, expr_in.symbol);
cout << ".\n";
return false;
}
NonterminalData &nonterminal=data.nonterminals[expr_in.nn];
nonterminal.is_used_in_IN_expressions=true;
nonterminal.where_it_is_used_in_IN_expressions.push_back(expr_in.symbol);
if(nn>=0)
{
PathData &path=data.derivation_paths[nn][expr_in.nn];
if(!path.v.size() || path.worst!=PathData::IN_EXPRESSION)
{
path.v.clear();
path.v.push_back(make_pair(expr_in.symbol, PathData::IN_EXPRESSION));
path.worst=PathData::IN_EXPRESSION;
}
}
return true;
}
else if(typeid(*expr)==typeid(NonterminalExpressionC_Constant))
{
NonterminalExpressionC_Constant &expr_const=*dynamic_cast<NonterminalExpressionC_Constant *>(expr);
if(!strcmp(expr_const.true_or_false->text, "true"))
expr_const.value=true;
else if(!strcmp(expr_const.true_or_false->text, "false"))
expr_const.value=false;
else
assert(false);
return true;
}
else
{
assert(false);
return false; // to please the compiler
}
}
bool check_whether_terminal_symbol_is_in_range(int tn, Terminal *location)
{
if(tn>=0 && tn<data.variables.alphabet_cardinality)
return true;
else
{
cout << "Out-of-range symbol " << tn << " at ";
print_terminal_location(cout, location);
cout << ".\n";
return false;
}
}
bool check_whether_terminal_symbol_is_in_range(vector<int> &v, Terminal *location)
{
vector<int> v2;
for(int i=0; i<v.size(); i++)
if(!(v[i]>=0 && v[i]<data.variables.alphabet_cardinality))
v2.push_back(v[i]);
if(v2.size())
{
cout << "Out-of-range symbol" << (v2.size()==1 ? " " : "s ");
for(int i=0; i<v2.size(); i++)
{
if(i)
{
if(i<v2.size()-1)
cout << ", ";
else
cout << " and ";
}
cout << v2[i];
}
cout << " in string at ";
print_terminal_location(cout, location);
cout << ".\n";
return false;
}
return true;
}
inline bool is_octal_digit(char c) { return c>='0' && c<='7'; }
bool decode_escape_sequences(char *s, vector<int> &v)
{
static char *escape_sequences="n\nt\tv\vb\br\rf\fa\a\\\\??\'\'\"\"";
int length=strlen(s);
assert(length>=2 && (s[0]=='\x27' || s[0]=='\x22') && s[0]==s[length-1]);
s[length-1]=0;
for(int i=1; s[i]; i++)
if(s[i]!='\\')
v.push_back(s[i]);
else
{
i++;
if(!s[i])
return false;
bool flag=false;
for(int j=0; escape_sequences[j]; j+=2)
if(s[i]==escape_sequences[j])
{
v.push_back(escape_sequences[j+1]);
flag=true;
break;
}
if(!flag)
{
if(s[i]=='x' || s[i]=='u' || s[i]=='U')
{
i++;
int j;
for(j=0; isxdigit(s[i+j]); j++);
if(s[i-1]=='x')
{
if(!j || j>8)
return false;
}
else if(s[i-1]=='u')
{
if(j>=4)
j=4;
else
return false;
}
else if(s[i-1]=='U')
{
if(j>=8)
j=8;
else
return false;
}
else
assert(false);
char backup=s[i+j];
s[i+j]=0;
int sn;
sscanf(s+i, "%x", &sn);
v.push_back(sn);
s[i+j]=backup;
i+=j-1;
}
else if(is_octal_digit(s[i]))
{
i++;
int j;
for(j=0; is_octal_digit(s[i+j]); j++);
if(!j || j>11 || (j==11 && s[i]>='3'))
return false;
int sn=0;
int factor=1;
for(int k=j+i-1; k>=i; k--)
{
sn+=(s[k]-'8')*factor;
factor*=8;
}
v.push_back(sn);
i+=j-1;
}
else
return false;
}
}
return true;
}
bool high_level_decode_escape_sequences(Terminal *t, string &s)
{
vector<int> v;
bool result=decode_escape_sequences(t->text, v);
if(!result)
{
cout << "Ill-formed escape sequences in string at ";
print_terminal_location(cout, t);
cout << ".\n";
return false;
}
bool flag=true;
for(int k=0; k<v.size(); k++)
if(!(v[k]>=0 && v[k]<data.variables.alphabet_cardinality))
{
cout << data.variables.alphabet_cardinality << "\n";
cout << "Out-of-range characters in string at ";
print_terminal_location(cout, t);
cout << ".\n";
flag=false;
break;
}
if(!flag)
return false;
s=""; // s.clear(); /* some old g++ does not have clear() :-( */
for(int k=0; k<v.size(); k++)
s+=char(v[k]);
return true;
}
bool get_character_from_the_string_that_is_expected_to_be_exactly_one_character_long(NonterminalExpressionS *expr_s, int nn, int &result)
{
if(!process_expression_proc(expr_s, nn, false))
return false;
if(expr_s->is_nts)
{
cout << "Expecting a string at ";
print_terminal_location(cout, expr_s->symbol);
cout << ".\n";
return false;
}
if(expr_s->s.size()!=1)
{
cout << "The string should be exactly one character long at ";
print_terminal_location(cout, expr_s->symbol);
cout << ".\n";
return false;
}
result=expr_s->s[0];
return true;
}
bool process_option_statement(NonterminalOptionStatement &option_statement)
{
char *s=option_statement.left->text; // make me const
#if 0
map<const char *, variable_base *, NullTerminatedStringCompare>::iterator p=data.variables.database.find(s);
if(p==data.variables.database.end())
{
cout << "Assignment to unknown variable '" << s << "' at ";
print_terminal_location(cout, option_statement.left);
cout << ".\n";
return false;
}
return true;
#endif
map<char *, AssignmentData, NullTerminatedStringCompare>::iterator p=data.assignments.find(s);
if(p!=data.assignments.end())
{
cout << "Duplicate assignment to variable '" << s << "' at ";
print_terminal_location(cout, option_statement.left);
cout << " (earlier assignment at ";
print_terminal_location(cout, (*p).second.declaration->left);
cout << ").\n";
return false;
}
if(!variable_exists(s))
{
cout << "Warning: assignment to unknown variable '" << s << "' at ";
print_terminal_location(cout, option_statement.left);
cout << " will probably have no effect.\n";
}
AssignmentData ad;
ad.declaration=&option_statement;
bool flag=true;
for(int j=0; j<option_statement.right.size(); j++)
{
char *s1=option_statement.right[j]->text;
char *final_s;
AssignmentData::ValueType vt;
if(!strcmp(s1, "true") || !strcmp(s1, "yes") || !strcmp(s1, "on"))
{
vt=AssignmentData::VALUE_TRUE;
final_s=s1;
}
else if(!strcmp(s1, "false") || !strcmp(s1, "no") || !strcmp(s1, "off"))
{
vt=AssignmentData::VALUE_FALSE;
final_s=s1;
}
else if(typeid(*option_statement.right[j])==typeid(Whale::TerminalId))
{
vt=AssignmentData::VALUE_ID;
final_s=s1;
}
else if(typeid(*option_statement.right[j])==typeid(Whale::TerminalString))
{
vt=AssignmentData::VALUE_STRING;
string str;
if(!high_level_decode_escape_sequences(option_statement.right[j], str))
{
flag=false;
continue;
}
final_s=strdup(str.c_str());
}
else if(typeid(*option_statement.right[j])==typeid(Whale::TerminalNumber))
{
vt=AssignmentData::VALUE_NUMBER;
final_s=s1;
}
else if(typeid(*option_statement.right[j])==typeid(Whale::TerminalHexNumber))
{
vt=AssignmentData::VALUE_HEX_NUMBER;
assert(s1[0]=='0' && tolower(s1[1])=='x' && s1[2]);
final_s=s1+2;
}
else if(typeid(*option_statement.right[j])==typeid(Whale::TerminalCode))
{
vt=AssignmentData::VALUE_CODE;
const char *s=option_statement.right[j]->text;
int k=(s[0]=='{' ? 1 : 2);
string str(s+k, s+strlen(s)-k);
final_s=strdup(str.c_str());
}
else
assert(false);
ad.values.push_back(std::make_pair(final_s, vt));
}
data.assignments[s]=ad;
return flag;
}
bool process_grammar(NonterminalS *S)
{
bool flag=true;
data.variables.alphabet_cardinality=256; // this assignment of a *temporary* value is a horrible hack. Ought to do it better.
for(int i=0; i<S->statements.size(); i++)
{
if(typeid(*S->statements[i])==typeid(NonterminalRuleStatement))
{
NonterminalRuleStatement &rule_statement=*dynamic_cast<NonterminalRuleStatement *>(S->statements[i]);
char *s=rule_statement.left->text;
int nn=data.find_nonterminal(s);
if(nn==-1)
{
NonterminalData new_nonterminal;
new_nonterminal.name=s; // it's not an error.
nn=data.nonterminals.size();
data.nonterminals.push_back(new_nonterminal);
}
NonterminalData &nonterminal=data.nonterminals[nn];
nonterminal.rules.push_back(&rule_statement);
}
else if(typeid(*S->statements[i])==typeid(NonterminalActionStatement))
{
// doing nothing by now
}
else if(typeid(*S->statements[i])==typeid(NonterminalStartConditionsStatement))
{
NonterminalStartConditionsStatement &start_conditions_statement=*dynamic_cast<NonterminalStartConditionsStatement *>(S->statements[i]);
for(int j=0; j<start_conditions_statement.names.size(); j++)
{
char *s=start_conditions_statement.names[j]->text;
int ssn=data.find_start_condition(s);
if(ssn==-1)
{
StartConditionData new_start_condition;
new_start_condition.name=s;
new_start_condition.declaration=start_conditions_statement.names[j];
ssn=data.start_conditions.size();
data.start_conditions.push_back(new_start_condition);
}
else
{
StartConditionData &start_condition=data.start_conditions[ssn];
cout << "Start condition ";
cout << "'" << start_condition.name << "'";
cout << ", declared at ";
print_terminal_location(cout, start_condition.declaration);
cout << ", is redeclared at ";
print_terminal_location(cout, start_conditions_statement.names[j]);
cout << "; redeclaration ignored.\n";
}
}
}
else if(typeid(*S->statements[i])==typeid(NonterminalOptionStatement))
{
bool result=process_option_statement(*dynamic_cast<NonterminalOptionStatement *>(S->statements[i]));
if(!result)
flag=false;
}
else if(typeid(*S->statements[i])==typeid(NonterminalInvalidStatement))
flag=false; // there was a parse error.
else
assert(false);
}
if(!data.start_conditions.size())
{
// if no start conditions were defined, a single start
// condition named 'INITIAL' should be created.
StartConditionData initial;
initial.name="INITIAL";
initial.declaration=NULL;
data.start_conditions.push_back(initial);
data.variables.start_conditions_enabled=false;
}
else
data.variables.start_conditions_enabled=true;
if(!assign_values_to_variables_stage_zero()) return false;
cout << "Alphabet cardinality is " << data.variables.alphabet_cardinality << ".\n";
int n=data.nonterminals.size();
data.derivation_paths.destructive_resize(n, n);
for(int i=0; i<n; i++)
{
NonterminalData &nonterminal=data.nonterminals[i];
for(int j=0; j<nonterminal.rules.size(); j++)
{
// Prof. Zhogolev would have killed me for this trick:
bool old_value=nonterminal.can_be_used_in_IN_expressions;
nonterminal.can_be_used_in_IN_expressions=true;
if(!process_expression_proc(nonterminal.rules[j]->right, i, true))
{
cout << nonterminal.name << " " << j << "\n";
flag=false;
}
if(!nonterminal.can_be_used_in_IN_expressions)
nonterminal.locations_of_offending_rules.push_back(nonterminal.rules[j]->arrow);
else
nonterminal.can_be_used_in_IN_expressions=old_value;
// I do feel ashamed, honestly!
}
}
for(int i=0; i<S->statements.size(); i++)
{
if(typeid(*S->statements[i])==typeid(NonterminalActionStatement))
{
NonterminalActionStatement &action_statement=*dynamic_cast<NonterminalActionStatement *>(S->statements[i]);
char *s;
bool is_special;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -