Predictive analysis of recursive descent: write an analysis process for each nonterminal.
requirement:
- The grammar used is as follows:
E →TE'
E → + TE' | ε
T → FT'
T →* FT' | ε
F → (E) | id - For any given input string (lexical token stream), the syntax is analyzed and the recursive descent method is implemented.
- There must be some error handling function. That is to say, we can prompt errors and ignore as few marks as possible to a certain extent for further analysis. You can refer to the set of synchronization marks described in the book.
Possible error conditions: ID ID * id, ID * * id, (id+id, + id*+id - The input string ends with ා, and outputs the production used in the derivation. For example:
Input: id+id*id#
Output: E → TE
T →FT
F →id
E →+ TE
T →FT
......
code
#include<iostream> using namespace std; static string ahead="";//Input token currently pending static string sub="";//Input after the current pending token is processed void E(); void E_();//For E ' void T(); void T_();//For T ' void F(); void error(); void match(string t); string nextToken(); int main() { //You don't have to type it yourself# char a[100]={};//Save user input, receive input, no more than 100 characters, otherwise getline will set failure bit, next input (if any) will be blocked, if necessary, can call cin.clear() to recover input cin.getline(a,100);//Enter means end of input sub=a; sub+='#'; ahead=nextToken(); E();//Because E is the start symbol return 0; } void E() { if(ahead=="("||ahead=="id")//First(T)={(,id} { cout<<"E→TE'"<<endl; T(); E_(); } else if(ahead==")"||ahead=="#")//Follow(E) is added to e's synchronization token set { // error(); //Error, but do not need to skip any mark, just skip E, i.E. do nothing ; } else//Error, the current token is not in the synchronization token collection of E, skipping the current token { //error(); ahead=nextToken(); E(); } } void E_() { if(ahead=="+") { cout<<"E'→+TE'"<<endl; match("+"); T(); E_(); } else if(ahead==")"||ahead=="#")//Follow(E ') = {), $}, where ාstands for$ { cout<<"E'→ε"<<endl; } else//Error, the current token is not in the synchronization token collection of E ', skipping the current token { //error(); ahead=nextToken(); E_(); } } void T() { if(ahead=="("||ahead=="id")//First(F)={(,id} { cout<<"T→FT'"<<endl; F(); T_(); } else if(ahead=="+"||ahead==")"||ahead=="#")//Follow(T) is added to the synchronization token set of T { // error(); //Error, but do not need to skip any mark, just skip T, that is, do nothing ; } else//Error, the current token is not in the synchronization token set of T, skipping the current token { //error(); ahead=nextToken(); T(); } } void T_() { if(ahead=="*") { cout<<"T'→*FT'"<<endl; match("*"); F(); T_(); } else if(ahead=="+"||ahead==")"||ahead=="#")//FOllow(T ') = {+,), $}, where ා represents$ { cout<<"T'→ε"<<endl; } else//Error, the current token is not in the synchronization token collection of T ', skipping the current token { //error(); ahead=nextToken(); T_(); } } void F() { if(ahead=="(") { cout<<"F→(E)"<<endl;; match("("); E(); match(")"); } else if(ahead=="id") { cout<<"F→id"<<endl;; match("id"); } else if(ahead=="+"||ahead=="*"||ahead==")"||ahead=="#")//Follow(F) is added to the synchronization token set of F { // error(); //Error, but do not need to skip any mark, skip F, that is, do not do any processing ; } else//Error, the current token is not in the synchronization token collection of F, skipping the current token { //error(); ahead=nextToken(); F(); } } void error() { cout<<"Match failed!!!"<<endl; } void match(string t) { if(ahead==t) { cout<<"matching"<<ahead<<endl; ahead=nextToken(); } else error(); } string nextToken()//Get next lexical token { if(sub.substr(0,2)=="id") { sub=sub.substr(2,sub.size()-2); return "id"; } else { string s=sub.substr(0,1); sub=sub.substr(1,sub.size()-1); return s; } }
Operation results
- It can be compared with the action in table 3.2 of P59, and it is found that it is consistent