Я нахожусь в середине класса компиляторов. Условия до сих пор: все мои токены хранятся в векторах, один как строковые литералы, а другой как Int для хранения типа (ключевого слова, идентификатора, оператора и т. Д. c.) Токена.
Мне бы хотелось получить ваш совет о том, как структурировать вызовы функций, и особенно ваши мысли о том, как я пытался изолировать часть выражения «выражение», и как я могу избежать рекурсии слева.
... Я написал соответствующие части своего кода, прежде чем вернуться сюда, чтобы подвести итог: я знаю, что хочу избежать левой рекурсии, читая рекурсивную часть после остальной части утверждения, но как Я могу это сделать? (то есть читая S = E + T по порядку, но анализируя его как «S =», затем либо «+ T;» и «E» или «T;» и «E +»)
Хуже, пример заданный профессором «вывод» программы в том же порядке, что и ввод, поэтому я не могу действительно прыгать по вектору, чтобы избежать его обработки не по порядку. Пример:
x=a + b;
выводится как
Token: Identifier Lexeme: x
<Statement List> -> <Statement> | <Statement> <Statement List>
<Statement> -> <Compound> | <Assign> | <If> | <Return> | <Print> | <Scan> | <While>
<Assign> -> <Identifier> = <Expression>;
Token: Operator Lexeme: =
Token: Identifier Lexeme: a
<Expression> -> <Term> <ExpressionPrime>
<Term> -> <Factor> <TermPrime>
<Factor> -> - <Primary> | <Primary>
<Primary> -> <Identifier> | <Integer> | <Identifier> ( <IDs> ) | ( <Expression> ) | <Real> | true | false
Token: Operator Lexeme: +
<Empty> -> Epsilon
<TermPrime> -> * <Factor> <TermPrime> | / <Factor> <TermPrime> | <Empty>
<Empty> -> Epsilon
<ExpressionPrime> -> + <Term> <ExpressionPrime> | - <Term> <ExpressionPrime> | <Empty>
Token: Identifier Lexeme: b
<Term> -> <Factor> <TermPrime>
<Factor> -> - <Primary> | <Primary>
<Primary> -> <Identifier> | <Integer> | <Identifier> ( <IDs> ) | ( <Expression> ) | <Real> | true | false
Token: Operator Lexeme: ;
<Empty> -> Epsilon
<TermPrime> -> * <Factor> <TermPrime> | / <Factor> <TermPrime> | <Empty>
<Empty> -> Epsilon
<ExpressionPrime> -> + <Term> <ExpressionPrime> | - <Term> <ExpressionPrime> | <Empty>
<Empty> -> Epsilon
В настоящее время мой код работает следующим образом:
IN MAIN -
There are 2 vectors:
1. Words has the string literals of the token
2. Token has the token type (stored as int)
I have 2 ints:
1. currLine keeps track of the offset from the start of the file to current line
2. offset tracks the int value returned by recursive functions
(each of which returns an int of how many tokens were processed
- i.e. "z = a+b;" would return 2 (z =) + 1 (a) + 1 (+) + 1 (b) +1 (;) for a total of 6)
while (currLine < Words.size())
// while the offset from the start of the file is smaller than the length of the vector
{
offset = statementType( words, token, (words.begin() + currLine), (token.begin() + currLine) );
// offset stores the number of tokens processed in the statement
if(offset > 0)
// error check, the code will return -1 if some function encounters an error
{
currLine += offset; // move the start of the next line to after the next ';'
cout << "current line moved up to " << currLine << endl;
}
//length <= 0 ? invalid
else
{
/* error! */
cout << "error found!" << endl;
break;
}
}
IN StatementType (вектор String words, вектор Int токен, итератор wordIt, итератор tokenIt)
, где итераторы используются для указания, где в векторе начинать сканирование
//currently, it detects the first token type and checks if it follows the formula
// if token[0] is a keyword, it's assumed to be a *declaration* - it checks token[1] to see if it's "="
// - if so, it checks to see if token[2] is an ID - if so, it checks to see if token[3] is ";"
// if all that is true, it returns 3 - if any besides the first are false, it returns -1 (for an error)
//the trick is the assignment statement
//if token[0] is an ID, it checks token[1] to see if it's "="
counter = evalPrimeExpr(words, token, wordit +2, tokenit +2);
// it passes the vectors to an Expression parser, with a slight offset on the iterators for the "beginning" location
if (counter >= 0) //if counter isn't an error, it's not -1
{
return 2 + counter;
}
else
{
return -1;
}
IN evalPrimeExpr-
//it counts up the tokens it reads until it reads a ";", then returns the count of tokens +1 (because the ";" is an escape/return trigger that returns before it loops again)
// while not end of vector
while ( (wordit + counter) != words.end() )
{
//add 1 to length of expression
cout << *(wordit + counter) << "\t expr token" << endl;
counter++;
//check if ';' found
if (*(wordit + counter) == ";")
{
// end of statement, ';' found
cout << *(wordit + counter) << "\t expr epsilon" << endl;
//return 2 ( ID = ) + counter (rest of statement including ;)
return 1+ counter;
}
//else continue
}