First version of the syntax definition: lexical items: number = any sequence of one or more decimal digits name = any sequence of letters, digits, or underline, first must be a letter, not case sensitive string = any sequence of characters except " or newline inside a pair of "s spaces, newlines, etc allowed between any two lexemes reserved words not case sensitive operator = + - * / % < <= <> > >= == and or grammar: ::= number | name | string | "read" | "(" ")" ::= | { "-" | "not" } ::= ( operator ) * ::= { "," } ::= "print" ::= name ":=" ::= "while" "do" ::= "if" "then" { "else" } ::= ( ";" ) * ::= "{" "}" ::= | | | | ::= const int nt_error = 0, nt_number = 1, nt_name = 2, nt_string = 3, nt_read = 4, nt_parenth = 5, nt_simple = 6, nt_expression = 7, nt_expr_list = 8, nt_print_stmt = 9, nt_assign_stmt = 10, nt_while_stmt = 11, nt_if_stmt = 12, nt_stmt_list = 13, nt_compound = 14; string node_names[] = { "error", "number", "name", "string", "read", "parenth", "simple", "expression", "expr-list", "print-stmt", "assign-stmt", "while-stmt", "if-stmt", "stmt-list", "compound" } const int num_node_names = sizeof(node_names) / sizeof(node_names[0]); struct node { int type; int int_val; string string_val; vector parts; node(int t, int v) { type = t; int_val = v; string_val = ""; } node(int t, string s) { type = t; int_val = 0; string_val = s; } node(int t, int v, string s) { type = t; int_val = v; string_val = s; } node(int t, string s, int v) { type = t; int_val = v; string_val = s; } ~node() { for (int i = 0; i < parts.size(); i += 1) delete parts[i]; } void add(node * n) { parts.push_back(n); } void print(int indent = 0) { cout << setw(4 * indent) << ""; if (type >= 0 && type < num_node_names) cout << node_names[type]; else cout << "bad(" << type << ")"; cout << " " << int_val << " \"" << string_val << "\"\n"; for (int i = 0; i < parts.size(); i += 1) parts[i].print(indent + 1); } };