📄 parser.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
#include "parser.h"
#include "token.h"
/*****************************************************************************
GetNextLine()
in:
istream &file - input source to read lines from
string &line - location for output line (only valid if return is true)
out:
boolean value indicating success
desc:
gets the next line as a string from the file, handling all comment removal
so that the calling function gets nothing but valid return data
******************************************************************************/
bool GetNextLine(istream &file, string &line){
static int lcount = 0;
static int comment = false;
line = "";
int indx;
while(line.empty() && !file.eof()){
getline(file, line, '\n');
lcount++;
// check for single line comments
line = line.substr(0, line.find(";")); // kill ";" style comments
line = line.substr(0, line.find("//")); // kill "//" style comments
// check for end of multiline comment
if(comment){
indx = line.find("*/");
// not found, ignore this line and get a new one
if(indx == string::npos){
line.erase();
continue;
}
// kill the comment part and continue processing
line.erase(0, indx + 2);
comment = false;
}
// check for start of multiline comment
indx = line.find("/*");
if(indx != string::npos){
int indx2 = 0;
// check to see if it ends on the same line
indx2 = line.find("*/", indx);
if(indx2 != string::npos) // yup, just erase the substr
line.erase(indx, (indx2 + 2) - indx);
else{ // nope, kill the end of this line and look for it on future lines
line = line.substr(0, indx); // kill "/*" style comments
comment = true;
}
}
replace(line.begin(), line.end(), '\t', ' '); // kill tabs
line.erase(0, line.find_first_not_of(" ")); // kill leading white space (also takes care of blank lines)
Token::CheckQuotes(line);
}
return !line.empty();
}
/*****************************************************************************
ExpandEnvironmentVariables()
in:
string line - line to check for variables
out:
string - converted line (may be unchanged if no env vars were found)
desc:
searches for the pattern $(variable name) in the environment and replaces
the reference in the string with the value. If not found the reference
in the string is still removed.
******************************************************************************/
string ExpandEnvironmentVariables(string line){
int open, close;
char *envvar; // has to be a char pointer for good reason
while((open = line.find("$(")) != string::npos){
if((close = line.find(")", open)) == string::npos){
cerr << "Error: Missig ')' on line '" << line << "'\n";
break;
}
// check to see if this is an assignment
if(0 && line.substr(close + 1, 2) == "=\""){
string env_var = line.substr(open + 2, close - (open + 2));
open = close + 3;
if((close = line.find("\"", open)) == string::npos){
cerr << "Error: Missing close \" on line '" << line << "'\n";
break;
}
env_var += "=" + line.substr(open, close - open);
_putenv(env_var.c_str());
line = "";
}
else{
// get the env setting if any
envvar = getenv(line.substr(open + 2, close - (open + 2)).c_str());
// remove the embeded variable
line.erase(open, close - open + 1);
// see if we should insert a value
if(!envvar) envvar = "false";
line.insert(open, envvar);
}
}
return line;
}
/*****************************************************************************
FudgeIfs()
in:
string line - line to check for if statement and fudge
out:
string - fudged line
desc:
standardize all if statemets to the following form...
basically just putting the env vars in $()'s for concistancy
if var=val -> if $(var)==val
if var -> if $(var)
if var ! -> if ! $(var)
******************************************************************************/
string FudgeIfs(string line){
// see if they $'d the vars already
if(line.find('$') != string::npos)
return line;
StringList temp = Token::tokenize(line);
if(!temp.empty() && temp[0] == "if"){
if(temp.size() < 2){
cerr << "\nError: invalid IF statement found:" << endl << line << endl;
exit(1);
}
// form new line
line.erase();
temp[1] = " $(" + temp[1] + ") ";
for(StringList::iterator itr = temp.begin(); itr != temp.end(); itr++){
if(itr + 1 != temp.end() && *(itr + 1) == "!")
itr->swap(*(itr +1));
else if(*itr == "=")
*itr = "==";
line += *itr + " ";
}
}
return line;
}
/*****************************************************************************
SkipLine()
in:
StringList token_list - list of tokens comprising a line
out:
boolean value indicating weather this line should be skipped, ie. true
return means the line evaluated to be a false conditional and can be
skipped.
desc:
Evaluating conditionals
'if' statments
--------------
If we are already ignoring, there is no decision, just increment
ignore_level again. Otherwise we check the conditional as follows
(remembering that undefined variables were removed in
ExpandEnvironmentVariables())
The defined syntax allows six possible combinations:
"if $(var) = val" - 4 token - env var defined = false if(var != val)
"if = val" - 3 token - env var not defined = false
"if $(var) " - 2 tokens - env var defined = true
"if " - 1 tokens - env var not defined = false
"if $(var) !" - 3 tokens - env var defined = !(true) -> false
"if !" - 2 tokens - env var not defined = !(false) -> true
"if (exp) && (expr)
therefore if the syntax is correct one can use the # of tokens
(1 or 3 or (4 with a compare)) to determin the 'falseness' of the statement
-> 1 token or 3 tokens or (4 tokens and var != val) then increment ignore level
'else' statements
-----------------
if we are NOT ignoring anything,
then ignore the 'else' block by assigning ignore_level = 1
if we are ignoring only ONE level deep,
then do the else by assigning ignore_level = 0
otherwise we are ignoring more than one level and the else makes no
difference what so ever!
'endif' statements
------------------
if we are ignoring anything,
then decriment ignore_level on an endif
******************************************************************************/
#define DEBUG_EXPR() 0
#if DEBUG_EXPR() == 1
#define DEBUG_EXPR() \
for(start = token_list.begin(); start != token_list.end(); start++) \
cout << *start << " "; \
cout << endl;
#endif
bool evaluate_expr(StringList token_list){
StringList::iterator start;
StringList::iterator end;
if(count(token_list.begin(), token_list.end(), "(") != count(token_list.begin(), token_list.end(), ")")){
for(start = token_list.begin(); start != token_list.end(); start++)
cerr << *start << " ";
cerr << "\nError: parse error in IF condition - missmatched parenthesis\n";
exit(1);
}
if(!token_list.empty() && token_list.front() == "if")
token_list.erase(token_list.begin());
DEBUG_EXPR();
// handle all ()'s and subexpressions
while((start = find(token_list.begin(), token_list.end(), "(")) != token_list.end()){
StringList::iterator temp;
temp = end = start;
do{
if((end = find(end + 1, token_list.end(), ")")) == token_list.end()){
for(start = token_list.begin(); start != token_list.end(); start++)
cerr << *start << " ";
cerr << "\nError: parse error in IF condition\n";
exit(1);
}
}while((temp = find(temp + 1, end, "(")) != end);
bool subexpr = evaluate_expr(StringList(start + 1, end));
start = token_list.erase(start, end + 1);
token_list.insert(start, subexpr ? "true" : "false");
}
DEBUG_EXPR();
// handle all !'s
while((start = find(token_list.begin(), token_list.end(), "!")) != token_list.end()){
*start = *(start + 1) == "false" ? "true" : "false";
token_list.erase(start + 1);
}
DEBUG_EXPR();
// handle all =='s and !='s
while((start = find(token_list.begin(), token_list.end(), "==")) != token_list.end()){
*(start - 1) = *(start - 1) == *(start + 1) ? "true" : "false";
token_list.erase(start, start + 2);
}
DEBUG_EXPR();
while((start = find(token_list.begin(), token_list.end(), "!=")) != token_list.end()){
*(start - 1) = *(start - 1) != *(start + 1) ? "true" : "false";
token_list.erase(start, start + 2);
}
DEBUG_EXPR();
while((start = find(token_list.begin(), token_list.end(), "&&")) != token_list.end()){
*(start - 1) = *(start - 1) != "false" && *(start + 1) != "false" ? "true" : "false";
token_list.erase(start, start + 2);
}
DEBUG_EXPR();
while((start = find(token_list.begin(), token_list.end(), "||")) != token_list.end()){
*(start - 1) = *(start - 1) != "false" || *(start + 1) != "false" ? "true" : "false";
token_list.erase(start, start + 2);
}
DEBUG_EXPR();
return token_list[0] != "false";
}
bool SkipLine(const StringList &token_list){
static int ignore_level = 0;
int last_level = ignore_level;
if(token_list.empty())
return ignore_level;
if(token_list[0] == "if"){
if(ignore_level || !evaluate_expr(token_list))
ignore_level++;
return true;
}
if(token_list[0] == "else"){
if(ignore_level == 0)
ignore_level = 1;
else if(ignore_level == 1)
ignore_level = 0;
return true;
}
if(token_list[0] == "endif"){
if(ignore_level)
ignore_level--;
return true;
}
return ignore_level;
}
/*****************************************************************************
IsSection()
in:
string token - token to check
out:
boolean value indicating match
desc:
checks token to see if it matches one of the predefined section names
******************************************************************************/
bool IsSection(const string &token){
if(token == MODULES ||
token == MEMORY ||
token == FILES ||
token == CONFIG )
return true;
return false;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -