Experimental requirements
[task introduction] the recursive descent analyzer is reformed to enable it to process once and complete syntax analysis and intermediate code translation at the same time.
[input] a complete source program.
[output] a quaternion sequence corresponding to the input.
[title] upgrade the program of Experiment 6, so that the program can generate an equivalent quaternion sequence for an input complete source program while doing recursive descent analysis.
Programming environment and language
Programming language: C++
IDE: vs 2019
Experimental principle analysis
The grammar of Experiment 6 is as follows:
<Block> → { <Decls> <STMTS> } <Decls> → <Type> <NameList> ; <Decls> | empty <NameList> → <Name> <NameList1> <NameList1> → , <Name> <NameList1> | empty <Type> → int <Name> → id <STMTS> → <STMT> <STMTS> | empty <STMT> → <Name> = <Expr> ; <STMT> → if ( <BOOL> ) <STMT> <STMT1> <STMT1> → else <STMT> | empty <STMT> → while ( <BOOL> ) <STMT> <BOOL> → <Expr> <RelOp> <Expr> <RelOp> → < | <= | > | >= | == | != <Expr> → <Term> <Expr1> <Expr1> → <AddOp> <Term> <Expr1> | empty <Term> → <Factor> <Term1> <Term1> → <MulOp> <Factor> <Term1> | empty <Factor> → id | number | ( <Expr> ) <AddOp> → + | - <MulOp> → * | /
In the previous syntax analysis part, I use recursive descent syntax analysis, so in the semantic analysis part, I need to use L-attribute grammar.
In this experiment, the format of my quaternion:
The format is roughly as follows: (op, arg1, arg2, result) The first is the operator, the second and third are the operands, and the fourth is the result of the operation.
1. Declaration statement, no quaternion is required
2. Assignment statement:
(=, value, _, id)
3. Conditional statements:
(jnz, BOOL, _, E.false) E.true: ... (jmp, _, _, S.next) E.false: ... S.next: ...
The quaternion of Boolean expression BOOL:
(op, arg1, arg2, result) result=1 express true,result=0 express false
4. Circular statement:
s: (jnz, BOOL, _, E.false) ... (jmp, _, _, s) E.false: ...
Analysis of key parts of the program
definition
char s[100][100] = { "\0" }; //Used to store initial data string str; //Used to store consolidated data int location = 0; //Used to locate arithmetic expressions bool flag = true; //Used to judge whether the arithmetic expression is legal string tree_map[100]; //Used to store syntax trees const int width = 3; //Set the interval to 3 char token[100] = { "\0" }; //Used to temporarily store words string error; //Used to record error messages string tetrad[100]; //Used to store quaternions int tetradNum = 0; //Record the number of quaternions struct IDs{ string name = ""; //The name of the identifier int type; //Because in the grammar definition, the data type has only int, there are only two values for type: 1 means int type and 0 means no type int value; //Value of identifier bool rel; //Storage for bool values }; IDs ID[100]; //Used to store the type and value of the identifier int IDNum = 0; //Number of identifiers used to record struct LInfo { int row; //Used to identify the rows and columns of the syntax tree int column; int interval = 0; //The space to be maintained between two subtrees int addr; //It is used to point to the addr quaternion to determine the jump address in conditional statements and loop statements IDs id; }; //It is used to store the information that needs to be passed by the L attribute grammar and the information needed to draw the syntax tree bool isKey(char* s); bool isOP(char* s); bool isDE(char& s); void pre_process(char* buff, int& in_comment); bool scanner(int k); char keywords[34][20] = { //There are 34 keywords, including main "auto", "short", "int", "long", "float", "double", "char", "struct", "union", "enum", "typedef", "const", "unsigned", "signed", "extern", "register", "static", "volatile", "void", "if", "else", "switch", "case", "for", "do", "while", "goto", "continue", "break", "default", "sizeof", "return", "main", "include" }; char operators[38][10] = { //Operators, 38 in total "+", "-", "*", "/", "%", "++", "--", "==", "!=", ">", ">=", "<", "<=", "&&", "||", "!", "=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", "&=", "^=", "|=", "&", "|", "^", "~", "<<", ">>", "?", ":", ",", ".", "->" }; char delimiters[7] = { '(', ')', '[', ']', '{', '}' , ';' }; //Separator, 7 in total int draw_line(int row, int num); void string_out(string s, int row, int column, int loc); int tree_out(string s, int row, int loc); void printTree(ofstream& fout); int readToken(); void bindString(int k); int findID(const string& words); void printSequence(ofstream& fout); LInfo Block(LInfo info); LInfo Decls(LInfo info); LInfo NameList(LInfo info); LInfo NameList1(LInfo info); bool Type(char* words); bool Name(char* words); LInfo STMTS(LInfo info); LInfo STMT(LInfo info); LInfo STMT1(LInfo info); LInfo BOOL(LInfo info); bool RelOp(char* words); LInfo Expr(LInfo info); LInfo Expr1(LInfo info); LInfo Term(LInfo info); LInfo Term1(LInfo info); LInfo Factor(LInfo info); bool AddOp(char* words); bool MulOp(char* words); int getData();
The differences between this experiment and Experiment 6 are as follows:
Firstly, the array of string type storing quaternions and the variable tetradNum determining the number of quaternions are declared (it is convenient to determine the jump position of conditional statements and circular statements):
string tetrad[100]; //Used to store quaternions int tetradNum = 0; //Record the number of quaternions
Secondly, two structures are declared. IDs is used to store the relevant attributes of id entifiers, and then an array of IDs type is created as a symbol table. IDNum and LInfo are used to transfer data between various grammar functions. These data include IDs type IDs in addition to some attributes used to construct syntax tree, which is convenient to transfer inheritance attributes and comprehensive attributes:
struct IDs{ string name = ""; //The name of the identifier int type; //Because in the grammar definition, the data type has only int, there are only two values for type: 1 means int type and 0 means no type int value; //Value of identifier bool rel; //Storage for bool values }; IDs ID[100]; //Used to store the type and value of the identifier int IDNum = 0; //Number of identifiers used to record struct LInfo { int row; //Used to identify the rows and columns of the syntax tree int column; int interval = 0; //The space to be maintained between two subtrees int addr; //It is used to point to the addr quaternion to determine the jump address in conditional statements and loop statements IDs id; }; //It is used to store the information that needs to be passed by the L attribute grammar and the information needed to draw the syntax tree
Then two functions are added. Findid (const string & words) is mainly used to find the identifier from the symbol table, and printsequence (OFSTREAM & fout) is used to output the quaternion to the file:
int findID(const string& words); void printSequence(ofstream& fout);
Finally, the parameter transfer of grammar function is changed by using the LInfo structure:
LInfo Block(LInfo info); LInfo Decls(LInfo info); LInfo NameList(LInfo info); LInfo NameList1(LInfo info); bool Type(char* words); bool Name(char* words); LInfo STMTS(LInfo info); LInfo STMT(LInfo info); LInfo STMT1(LInfo info); LInfo BOOL(LInfo info); bool RelOp(char* words); LInfo Expr(LInfo info); LInfo Expr1(LInfo info); LInfo Term(LInfo info); LInfo Term1(LInfo info); LInfo Factor(LInfo info); bool AddOp(char* words); bool MulOp(char* words);
Analysis of key parts
Lexical analysis will not be repeated here.
Construct related functions of syntax tree:
int draw_line(int row, int num) { //It is used to draw a horizontal line to separate sibling nodes and return to the starting position of the next start tree_map[row].append(num, '-'); return tree_map[row].size(); } /**Used to output string * Where column is the starting position of the row and loc is the position of the vertical line in the previous row, * loc The default value is 0, which means there is no vertical bar. At this time, the string is put into the corresponding position through column * If it is not 0, the position of the string is processed through loc */ void string_out(string s, int row, int column, int loc = 0) { if (loc == 0) { if (tree_map[row].size() < column) { //If not, it means that the middle needs to be filled with spaces int n = column - tree_map[row].size(); tree_map[row].append(n, ' '); } tree_map[row].append(s); } else { int n1 = s.size() / 2; if (loc - n1 <= column) { //If the length of the node is longer than the parent node, it is added through column if (tree_map[row].size() < column) { //If not, it means that the middle needs to be filled with spaces int n = column - tree_map[row].size(); tree_map[row].append(n, ' '); } tree_map[row].append(s); } else { //In this case, spaces must be filled in int n = loc - n1 - tree_map[row].size(); tree_map[row].append(n, ' '); tree_map[row].append(s); } } } /**Draw a vertical line between the parent and child nodes, s represents the character of the parent node, and loc represents the starting position of the parent node * The return value is used to handle the position of the operator */ int tree_out(string s, int row, int column) { int n1 = s.size() / 2; int n2 = column + n1 - tree_map[row].size(); tree_map[row].append(n2, ' '); tree_map[row] += '|'; return n1 + column; } void printTree(ofstream& fout) { for (int i = 0; i < 100; i++) { if (!tree_map[i].empty()) { fout << tree_map[i] << endl; } else break; } }
Then there are some other functions:
int readToken() { //It is used to take a word from str according to the space and return the length of the word for shift operation int i = 0; for (; str[location + i] != ' '; i++) { token[i] = str[location + i]; } token[i] = '\0'; return i; } void bindString(int k) { //Used to integrate the contents of the s array into str for (int i = 0; i <= k; i++) { str.append(s[i]); } } int findID(const string& words) { //Search from the symbol table. If it is found, it returns the corresponding position; otherwise, it returns - 1 for (int i = 0; i < IDNum; i++) { if (words == ID[i].name) return i; } return -1; } void printSequence(ofstream& fout) { for (int i = 0; i < tetradNum; i++) { fout << i << " : " << tetrad[i] << endl; } } int getData() { int k = 0; cout << "Please enter a code block(#Indicates the end): "< < endl; cin.getline(s[0], 100); while (k < 100 && strcmp(s[k], "#") != 0) { cin.getline(s[++k], 100); } return k; }
The last is the most critical part:
LInfo Block(LInfo info) { if (flag) { string_out("<Block>", info.row, info.column); int loc = tree_out("<Block>", ++info.row, info.column); int i = readToken(); if (strcmp(token, "{") == 0) { location = location + i + 1; string_out(token, ++info.row, info.column, loc); info.column = draw_line(info.row, width); LInfo info1 = Decls(info); if (!flag) return info; info.column = draw_line(info.row, info1.interval + width); LInfo info2 = STMTS(info); if (!flag) return info; info.column = draw_line(info.row, info2.interval + width); i = readToken(); if (strcmp(token, "}") == 0) { location = location + i + 1; string_out(token, info.row, info.column); info.interval = info1.interval + info2.interval + width * 3 + 1 + 7; return info; } else { string s = token; error = s + "Previously missing}"; flag = false; return info; } } else { string s = token; error = s + "Previously missing{"; flag = false; return info; } } } LInfo Decls(LInfo info) { if (flag) { string_out("<Decls>", info.row, info.column); int loc = tree_out("<Decls>", ++info.row, info.column); int i = readToken(); if (Type(token)) { info.id.type = 1; //Mark the current type as int location = location + i + 1; string_out("<Type>", ++info.row, info.column, loc); loc = tree_out("<Type>", info.row + 1, info.column); string_out(token, info.row + 2, info.column, loc); info.column = draw_line(info.row, width); LInfo info1 = NameList(info); if (!flag) return info; info.column = draw_line(info.row, info1.interval + width); i = readToken(); if (strcmp(token, ";") == 0) { location = location + i + 1; string_out(token, info.row, info.column); info.column = draw_line(info.row, width); LInfo info2 = Decls(info); if (!flag) return info; info.interval = info1.interval + info2.interval + width * 3 + 1 + 7; return info; } else { string s = token; error = s + "Previously missing;"; flag = false; return info; } } else { //Otherwise, the output is empty string_out("empty", ++info.row, info.column, loc); info.interval = 7; return info; } } } LInfo NameList(LInfo info) { if (flag) { string_out("<NameList>", info.row, info.column); int loc = tree_out("<NameList>", ++info.row, info.column); int i = readToken(); if (Name(token)) { ID[IDNum].name = token; //Store identifier in symbol table ID[IDNum].type = info.id.type; IDNum++; location = location + i + 1; string_out("<Name>", ++info.row, info.column, loc); loc = tree_out("<Name>", info.row + 1, info.column + 2); string_out(token, info.row + 2, info.column, loc); info.column = draw_line(info.row, width); LInfo info1 = NameList1(info); if (!flag) return info; info.interval = info1.interval + width + 10; return info; } else { string s = token; error = s + "Previously missing id"; flag = false; return info; } } } LInfo NameList1(LInfo info) { if (flag) { string_out("<NameList1>", info.row, info.column); int loc = tree_out("<NameList1>", ++info.row, info.column); int i = readToken(); if (strcmp(token, ",") == 0) { location = location + i + 1; string_out(token, ++info.row, info.column, loc); info.column = draw_line(info.row, width); i = readToken(); if (Name(token)) { ID[IDNum].name = token; //Store identifier in symbol table ID[IDNum].type = info.id.type; IDNum++; location = location + i + 1; string_out("<Name>", ++info.row, info.column); tree_out("<Name>", info.row + 1, info.column); string_out(token, info.row + 2, info.column); info.column = draw_line(info.row, width); LInfo info1 = NameList1(info); if (!flag) return info; info.interval = info1.interval + 6 + width * 2 + 11; return info; } else { string s = token; error = s + "Previously missing id"; flag = false; return info; } } else { //Otherwise, the output is empty string_out("empty", ++info.row, info.column, loc); info.interval = 11; return info; } } } bool Type(char* words) { if (strcmp(words, "int") == 0) return true; else return false; } bool Name(char* words) { if (!isOP(words) && !isKey(words) && !isDE(words[0]) && !isdigit(words[0]) && words[0] != '\'' && words[0] != '\"') { if (words[0] == '_' || isalpha(words[0])) return true; } return false; } LInfo STMTS(LInfo info) { if (flag) { string_out("<STMTS>", info.row, info.column); int loc = tree_out("<STMTS>", ++info.row, info.column); int i = readToken(); if (Name(token) || strcmp(token, "if") == 0 || strcmp(token, "while") == 0) { ++info.row; LInfo info1 = STMT(info); if (!flag) return info; info.column = draw_line(info.row, info1.interval + width); LInfo info2 = STMTS(info); if (!flag) return info; info.interval = info1.interval + info2.interval + 7; return info; } else { //Otherwise, the output is empty string_out("empty", ++info.row, info.column, loc); info.interval = 7; return info; } } } LInfo STMT(LInfo info) { if (flag) { string_out("<STMT>", info.row, info.column); int loc = tree_out("<STMT>", ++info.row, info.column); int i = readToken(); location = location + i + 1; if (Name(token)) { //If identifier int num = findID(token); if (num == -1) { //Because it is an assignment statement, you first need to judge whether the identifier has been declared before. If not, an error will be reported string s = token; error = "identifier \"" + s + "\"Undeclared"; flag = false; return info; } string_out("<Name>", ++info.row, info.column, loc); tree_out("<Name>", info.row + 1, info.column); string_out(token, info.row + 2, info.column, loc); info.column = draw_line(info.row, width); i = readToken(); if (strcmp(token, "=") == 0) { location = location + i + 1; string_out(token, info.row, info.column); info.column = draw_line(info.row, width); LInfo info1 = Expr(info); if (!flag) return info; ID[num].value = info1.id.value; tetrad[tetradNum++] = "(=, " + to_string(info1.id.value) + ", _, " + ID[num].name + ")"; info.column = draw_line(info.row, info1.interval + width); i = readToken(); if (strcmp(token, ";") == 0) { location = location + i + 1; string_out(token, info.row, info.column); info.interval = info1.interval + width * 3 + 2 + 6; return info; } else { string s = token; error = s + "Previously missing;"; flag = false; return info; } } else { string s = token; error = s + "Previously missing="; flag = false; return info; } } else if (strcmp(token, "if") == 0) { string_out(token, ++info.row, info.column, loc); info.column = draw_line(info.row, width); i = readToken(); if (strcmp(token, "(") == 0) { location = location + i + 1; string_out(token, info.row, info.column); info.column = draw_line(info.row, width); LInfo info1 = BOOL(info); if (!flag) return info; info.column = draw_line(info.row, info1.interval + width); tetrad[tetradNum++] = "(jnz, BOOL, _, "; info.addr = tetradNum - 1; i = readToken(); if (strcmp(token, ")") == 0) { location = location + i + 1; string_out(token, info.row, info.column); info.column = draw_line(info.row, width); LInfo info2 = STMT(info); if (!flag) return info; info.column = draw_line(info.row, info2.interval + width); tetrad[tetradNum++] = "(jmp, _, _, "; tetrad[info.addr] = tetrad[info.addr] + to_string(tetradNum) + ")"; info.addr = tetradNum - 1; LInfo info3 = STMT1(info); if (!flag) return info; info.interval = info1.interval + info2.interval + info3.interval + width * 5 + 2 + 6; tetrad[info.addr] = tetrad[info.addr] + to_string(tetradNum) + ")"; return info; } else { string s = token; error = s + "Previously missing)"; flag = false; return info; } } else { string s = token; error = s + "Previously missing("; flag = false; return info; } } else if (strcmp(token, "while") == 0) { string_out(token, ++info.row, info.column, loc); info.column = draw_line(info.row, width); i = readToken(); if (strcmp(token, "(") == 0) { location = location + i + 1; string_out(token, info.row, info.column); info.column = draw_line(info.row, width); LInfo info1 = BOOL(info); if (!flag) return info; info.column = draw_line(info.row, info1.interval + width); i = readToken(); if (strcmp(token, ")") == 0) { location = location + i + 1; string_out(token, info.row, info.column); info.column = draw_line(info.row, width); tetrad[tetradNum++] = "(jnz, BOOL, _, "; info.addr = tetradNum - 1; LInfo info2 = STMT(info); if (!flag) return info; tetrad[tetradNum++] = "(jmp, _, _, " + to_string(info.addr) + ")"; tetrad[info.addr] = tetrad[info.addr] + to_string(tetradNum) + ")"; info.interval = info1.interval + info2.interval + width * 4 + 2 + 6; return info; } else { string s = token; error = s + "Previously missing)"; flag = false; return info; } } else { string s = token; error = s + "Previously missing("; flag = false; return info; } } else { string s = token; error = s + "Previously missing id"; flag = false; return info; } } } LInfo STMT1(LInfo info) { if (flag) { string_out("<STMT1>", info.row, info.column); int loc = tree_out("<STMT1>", ++info.row, info.column); int i = readToken(); if (strcmp(token, "else") == 0) { location = location + i + 1; string_out(token, ++info.row, info.column, loc); info.column = draw_line(info.row, width); LInfo info1 = STMT(info); if (!flag) return info; info.interval = info1.interval + width + 7; return info; } else { //Otherwise, the output is empty string_out("empty", ++info.row, info.column, loc); info.interval = 7; return info; } } } LInfo BOOL(LInfo info) { if (flag) { string_out("<BOOL>", info.row, info.column); tree_out("<BOOL>", ++info.row, info.column); ++info.row; LInfo info1 = Expr(info); if (!flag) return info; info.column = draw_line(info.row, info1.interval + width); int i = readToken(); if (RelOp(token)) { //If it is a relational operator location = location + i + 1; string_out("<RelOp>", info.row, info.column); int loc = tree_out("<RelOp>", info.row + 1, info.column); string_out(token, info.row + 2, loc); info.column = draw_line(info.row, width); string temp = token; LInfo info2 = Expr(info); if (!flag) return info; if (temp == "<") { //Due to the characteristics of C + +, the output result here is 1 for true and 0 for false bool result = info1.id.value < info2.id.value; tetrad[tetradNum++] = "(<, " + to_string(info1.id.value) + ", " + to_string(info2.id.value) + ", " + to_string(result) + ")"; info.id.rel = result; } else if (temp == "<=") { bool result = info1.id.value <= info2.id.value; tetrad[tetradNum++] = "(<=, " + to_string(info1.id.value) + ", " + to_string(info2.id.value) + ", " + to_string(result) + ")"; info.id.rel = result; } else if (temp == ">") { bool result = info1.id.value > info2.id.value; tetrad[tetradNum++] = "(>, " + to_string(info1.id.value) + ", " + to_string(info2.id.value) + ", " + to_string(result) + ")"; info.id.rel = result; } else if (temp == ">=") { bool result = info1.id.value >= info2.id.value; tetrad[tetradNum++] = "(>=, " + to_string(info1.id.value) + ", " + to_string(info2.id.value) + ", " + to_string(result) + ")"; info.id.rel = result; } else if (temp == "==") { bool result = info1.id.value == info2.id.value; tetrad[tetradNum++] = "(==, " + to_string(info1.id.value) + ", " + to_string(info2.id.value) + ", " + to_string(result) + ")"; info.id.rel = result; } else { bool result = info1.id.value != info2.id.value; tetrad[tetradNum++] = "(!=, " + to_string(info1.id.value) + ", " + to_string(info2.id.value) + ", " + to_string(result) + ")"; info.id.rel = result; } info.interval = info1.interval + info2.interval + width * 2 + 6; return info; } else { string s = token; error = s + "Missing relational operator before"; flag = false; return info; } } } bool RelOp(char* words) { if (strcmp(words, "<") == 0 || strcmp(words, "<=") == 0 || strcmp(words, ">") == 0 || strcmp(words, ">=") == 0 || strcmp(words, "==") == 0 || strcmp(words, "!=") == 0) { return true; }return false; } LInfo Expr(LInfo info) { if (flag) { string_out("<Expr>", info.row, info.column); tree_out("<Expr>", ++info.row, info.column); ++info.row; LInfo info1 = Term(info); if (!flag) return info; info.column = draw_line(info.row, info1.interval + width); info.id = info1.id; LInfo info2 = Expr1(info); if (!flag) return info; info.interval = info1.interval + info2.interval + width + 6; info.id = info2.id; return info; } } LInfo Expr1(LInfo info) { if (flag) { string_out("<Expr1>", info.row, info.column); int loc = tree_out("<Expr1>", ++info.row, info.column); int i = readToken(); if (AddOp(token)) { //If the character is + or- location = location + i + 1; string_out("<AddOp>", ++info.row, info.column, loc); loc = tree_out("<AddOp>", info.row + 1, info.column); string_out(token, info.row + 2, info.column, loc); info.column = draw_line(info.row, width); string temp = token; LInfo info1 = Term(info); if (!flag) return info; if (temp == "+") { int result = info.id.value + info1.id.value; tetrad[tetradNum++] = "(+, " + to_string(info.id.value) + ", " + to_string(info1.id.value) + ", " + to_string(result) + ")"; info.id.value = result; } else { int result = info.id.value - info1.id.value; tetrad[tetradNum++] = "(-, " + to_string(info.id.value) + ", " + to_string(info1.id.value) + ", " + to_string(result) + ")"; info.id.value = result; } info.column = draw_line(info.row, info1.interval + width); LInfo info2 = Expr1(info); if (!flag) return info; info.interval = info1.interval + info2.interval + width * 2 + 7; info.id = info2.id; return info; } else { //Otherwise, the output is empty string_out("empty", ++info.row, info.column, loc); info.interval = 7; return info; } } } LInfo Term(LInfo info) { if (flag) { string_out("<Term>", info.row, info.column); tree_out("<Term>", ++info.row, info.column); ++info.row; LInfo info1 = Factor(info); if (!flag) return info; info.column = draw_line(info.row, info1.interval + width); info.id = info1.id; LInfo info2 = Term1(info); if (!flag) return info; info.interval = info1.interval + info2.interval + width + 6; info.id = info2.id; return info; } } LInfo Term1(LInfo info) { if (flag) { string_out("<Term1>", info.row, info.column); int loc = tree_out("<Term1>", ++info.row, info.column); int i = readToken(); if (MulOp(token)) { //If the character is * or/ location = location + i + 1; string_out("<MulOp>", ++info.row, info.column, loc); loc = tree_out("<MulOp>", info.row + 1, info.column); string_out(token, info.row + 2, info.column, loc); info.column = draw_line(info.row, width); string temp = token; LInfo info1 = Factor(info); if (!flag) return info; if (temp == "*") { int result = info.id.value * info1.id.value; tetrad[tetradNum++] = "(*, " + to_string(info.id.value) + ", " + to_string(info1.id.value) + ", " + to_string(result) + ")"; info.id.value = result; } else { int result = info.id.value / info1.id.value; tetrad[tetradNum++] = "(/, " + to_string(info.id.value) + ", " + to_string(info1.id.value) + ", " + to_string(result) + ")"; info.id.value = result; } info.column = draw_line(info.row, info1.interval + width); LInfo info2 = Term1(info); if (!flag) return info; info.interval = info1.interval + info2.interval + width * 2 + 7; info.id = info2.id; return info; } else { //Otherwise, the output is empty string_out("empty", ++info.row, info.column, loc); info.interval = 7; return info; } } } LInfo Factor(LInfo info) { if (flag) { string_out("<Factor>", info.row, info.column); int loc = tree_out("<Factor>", ++info.row, info.column); int i = readToken(); location = location + i + 1; if (Name(token)) { int num = findID(token); if (num == -1) { string s = token; error = "identifier \"" + s + "\"Undeclared"; flag = false; return info; } info.id = ID[num]; string_out(token, ++info.row, info.column, loc); info.interval = 8; return info; } else if (isdigit(token[0])) { LInfo info1; info1.id.value = atoi(token); info1.id.type = 1; info.id = info1.id; string_out(token, ++info.row, info.column, loc); info.interval = 8; return info; } else if (strcmp(token, "(") == 0) { string_out(token, ++info.row, info.column, loc); info.column = draw_line(info.row, width); LInfo info1 = Expr(info); if (!flag) return info; i = readToken(); if (strcmp(token, ")") == 0) { location = location + i + 1; info.column = draw_line(info.row, info1.interval + width); string_out(token, info.row, info.column); info.interval = info1.interval + width * 2 + 8; info.id = info1.id; return info; } else { //If not, it indicates that the arithmetic expression is wrong string s = token; error = s + "Previously missing)"; flag = false; return info; } } else { string s = token; error = s + "Previously missing id"; flag = false; return info; } } } bool AddOp(char* words) { if (strcmp(words, "+") == 0 || strcmp(words, "-") == 0)return true; return false; } bool MulOp(char* words) { if (strcmp(words, "*") == 0 || strcmp(words, "/") == 0)return true; return false; }
Then there is the main() function:
int main() { int k = getData(); //Get input if (scanner(k)) { //Lexical analysis first bindString(k); //Integrate multiple lines of input data into a str of type string cout << str << endl; LInfo info; info.row = info.column = 0; Block(info); //Enter parsing if (str[location] == '#') { cout << "Correct!" << endl; cout << "Next, output the syntax tree!" << endl; ofstream fout("TreeOut.txt"); printTree(fout); cout << "Syntax tree output succeeded!Enclosed please find TreeOut.txt file!" << endl; fout.close(); fout.open("output.txt"); printSequence(fout); fout.close(); cout << "Quaternion output succeeded!Enclosed please find output.txt file!" << endl; } else { cout << "Error!Parsing failed!" << endl; cout << error << endl; //Output error message } } else { cout << "Error!Pretreatment failed!" << endl; } return 0; }
Program test
1. Test case 1:
{ int x; x=1; if(x!=1) x=2; x=3; } #
The operation results are as follows:
2. Test case 2:
{ x=1; } #
The operation results are as follows:
It can be seen that since the variable x is not declared before assignment, an error message should be given.
3. Test case 3:
{ int x; x =1; while(x<4) x= x+1; x=5; } #
The operation results are as follows:
I found a total of three test cases to test the quaternion translation results of declaration statement, assignment statement, conditional statement and circular statement respectively. If there is an undeclared variable name in other statements, an error should be reported to indicate that the variable name is undeclared. From the above test cases, we can see that these functions have been realized.