Task: Recursive descent parser generator


C++: #include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <map>
#include <set>
#include <regex>
using namespace std;

map<string, string> terminals;
map<string, vector<vector<string>>> nonterminalRules;
map<string, set<string>> nonterminalFirst;
map<string, vector<string>> nonterminalCode;

int main(int argc, char **argv) {
	if (argc < 3) {
		cout << "Usage: <input file> <output file>" << endl;
		return 1;
	}

	ifstream inFile(argv[1]);
	ofstream outFile(argv[2]);

	regex blankLine(R"(^\s*$)");
	regex terminalPattern(R"((\w+)\s+(.+))");
	regex rulePattern(R"(^!!\s*(\w+)\s*->\s*((?:\w+\s*)*)$)");
	regex argPattern(R"(\$(\d+))");
	smatch results;

	
	string line;
	while (true) {
		getline(inFile, line);

		
		if (regex_match(line, blankLine))
			break;

		regex_match(line, results, terminalPattern);
		terminals[results[1]] = results[2];
	}

	outFile << "#include <iostream>" << endl;
	outFile << "#include <fstream>" << endl;
	outFile << "#include <string>" << endl;
	outFile << "#include <regex>" << endl;
	outFile << "using namespace std;" << endl << endl;

	
	outFile << "string input, nextToken, nextTokenValue;" << endl;
	outFile << "string prevToken, prevTokenValue;" << endl << endl;

	outFile << "void advanceToken() {" << endl;
	outFile << "	static smatch results;" << endl << endl;

	outFile << "	prevToken = nextToken;" << endl;
	outFile << "	prevTokenValue = nextTokenValue;" << endl << endl;

	for (auto i = terminals.begin(); i != terminals.end(); ++i) {
		string name = i->first + "_pattern";
		string pattern = i->second;

		outFile << "	static regex " << name << "(R\"(^\\s*(" << pattern << "))\");" << endl;
		outFile << "	if (regex_search(input, results, " << name << ", regex_constants::match_continuous)) {" << endl;
		outFile << "		nextToken = \"" << i->first << "\";" << endl;
		outFile << "		nextTokenValue = results[1];" << endl;
		outFile << "		input = regex_replace(input, " << name << ", \"\");" << endl;
		outFile << "		return;" << endl;
		outFile << "	}" << endl << endl;
	}

	outFile << "	static regex eof(R\"(\\s*)\");" << endl;
	outFile << "	if (regex_match(input, results, eof, regex_constants::match_continuous)) {" << endl;
	outFile << "		nextToken = \"\";" << endl;
	outFile << "		nextTokenValue = \"\";" << endl;
	outFile << "		return;" << endl;
	outFile << "	}" << endl << endl;

	outFile << "	throw \"Unknown token\";" << endl;
	outFile << "}" << endl << endl;

	outFile << "bool same(string symbol) {" << endl;
	outFile << "	if (symbol == nextToken) {" << endl;
	outFile << "		advanceToken();" << endl;
	outFile << "		return true;" << endl;
	outFile << "	}" << endl;
	outFile << "	return false;" << endl;
	outFile << "}" << endl << endl;

	
	while (true) {
		getline(inFile, line);
		
		
		if (regex_match(line, results, rulePattern))
			break;

		outFile << line << endl;
	}

	
	while (true) {
		
		string name = results[1];
		stringstream ss(results[2]);

		string tempString;
		vector<string> tempVector;
		while (ss >> tempString)
			tempVector.push_back(tempString);
		nonterminalRules[name].push_back(tempVector);

		
		string code = "";
		while (true) {
			getline(inFile, line);

			if (!inFile || regex_match(line, results, rulePattern))
				break;

			
			line = regex_replace(line, argPattern, "results[$1]");

			code += line + "\n";
		}
		nonterminalCode[name].push_back(code);

		
		if (!inFile)
			break;
	}

	
	bool done = false;
	while (!done)
		for (auto i = nonterminalRules.begin(); i != nonterminalRules.end(); ++i) {
			string name = i->first;
			done = true; 

			if (nonterminalFirst.find(i->first) == nonterminalFirst.end())
				nonterminalFirst[i->first] = set<string>();

			for (int j = 0; j < i->second.size(); ++j) {
				if (i->second[j].size() == 0)
					nonterminalFirst[i->first].insert("");
				else {
					string first = i->second[j][0];
					if (nonterminalFirst.find(first) != nonterminalFirst.end()) {
						for (auto k = nonterminalFirst[first].begin(); k != nonterminalFirst[first].end(); ++k) {
							if (nonterminalFirst[name].find(*k) == nonterminalFirst[name].end()) {
								nonterminalFirst[name].insert(*k);
								done = false;
							}
						}
					} else if (nonterminalFirst[name].find(first) == nonterminalFirst[name].end()) {
						nonterminalFirst[name].insert(first);
						done = false;
					}
				}
			}
		}

	
	for (auto i = nonterminalRules.begin(); i != nonterminalRules.end(); ++i) {
		string name = i->first + "_rule";
		outFile << "string " << name << "();" << endl;
	}
	outFile << endl;

	
	for (auto i = nonterminalRules.begin(); i != nonterminalRules.end(); ++i) {
		string name = i->first + "_rule";
		outFile << "string " << name << "() {" << endl;
		outFile << "	vector<string> results;" << endl;
		outFile << "	results.push_back(\"\");" << endl << endl;
		
		
		int epsilon = -1;
		for (int j = 0; epsilon == -1 && j < i->second.size(); ++j)
			if (i->second[j].size() == 0)
				epsilon = j;

		
		for (int j = 0; j < i->second.size(); ++j) {
			
			if (j == epsilon)
				continue;

			string token = i->second[j][0];
			if (terminals.find(token) != terminals.end())
				outFile << "	if (nextToken == \"" << i->second[j][0] << "\") {" << endl;
			else {
				outFile << "	if (";
				bool first = true;
				for (auto k = nonterminalFirst[token].begin(); k != nonterminalFirst[token].end(); ++k, first = false) {
					if (!first)
						outFile << " || ";
					outFile << "nextToken == \"" << (*k) << "\"";
				}
				outFile << ") {" << endl;
			}
			
			for (int k = 0; k < i->second[j].size(); ++k) {
				if (terminals.find(i->second[j][k]) != terminals.end()) {
					outFile << "		if(same(\"" << i->second[j][k] << "\"))" << endl;
					outFile << "			results.push_back(prevTokenValue);" << endl;
					outFile << "		else" << endl;
					outFile << "			throw \"Syntax error - mismatched token\";" << endl;
				} else
					outFile << "		results.push_back(" << i->second[j][k] << "_rule());" << endl;
			}

			
			outFile << nonterminalCode[i->first][j];

			outFile << "	}" << endl << endl;
		}

		if (epsilon == -1)
			outFile << "	throw \"Syntax error - unmatched token\";" << endl;
		else
			outFile << nonterminalCode[i->first][epsilon];

		outFile << "}" << endl << endl;
	}

	
	outFile << "int main(int argc, char **argv) {" << endl;
	outFile << "	if(argc < 2) {" << endl;
	outFile << "		cout << \"Usage: <input file>\" << endl;" << endl;
	outFile << "		return 1;" << endl;
	outFile << "	}" << endl << endl;

	outFile << "	ifstream file(argv[1]);" << endl;
	outFile << "	string line;" << endl;
	outFile << "	input = \"\";" << endl << endl;

	outFile << "	while(true) {" << endl;
	outFile << "		getline(file, line);" << endl;
	outFile << "		if(!file) break;" << endl;
	outFile << "		input += line + \"\\n\";" << endl;
	outFile << "	}" << endl << endl;

	outFile << "	advanceToken();" << endl << endl;

	outFile << "	start_rule();" << endl;
	outFile << "}" << endl;
}



Go: package main

import (
    "fmt"
    "go/ast"
    "go/parser"
    "log"
)

func labelStr(label int) string {
    return fmt.Sprintf("_%04d", label)
}

type binexp struct {
    op, left, right string
    kind, index     int
}

func main() {
    x := "(one + two) * three - four * five"
    fmt.Println("Expression to parse: ", x)
    f, err := parser.ParseExpr(x)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("\nThe abstract syntax tree for this expression:")
    ast.Print(nil, f)

    fmt.Println("\nThe corresponding three-address code:")
    var binexps []binexp
    
    ast.Inspect(f, func(n ast.Node) bool {
        switch x := n.(type) {
        case *ast.BinaryExpr:
            sx, ok1 := x.X.(*ast.Ident)
            sy, ok2 := x.Y.(*ast.Ident)
            op := x.Op.String()
            if ok1 && ok2 {
                binexps = append(binexps, binexp{op, sx.Name, sy.Name, 3, 0})
            } else if !ok1 && ok2 {
                binexps = append(binexps, binexp{op, "<addr>", sy.Name, 2, 0})
            } else if ok1 && !ok2 {
                binexps = append(binexps, binexp{op, sx.Name, "<addr>", 1, 0})
            } else {
                binexps = append(binexps, binexp{op, "<addr>", "<addr>", 0, 0})
            }
        }
        return true
    })

    for i := 0; i < len(binexps); i++ {
        binexps[i].index = i
    }

    label, last := 0, -1
    var ops, args []binexp
    var labels []string
    for i, be := range binexps {
        if be.kind == 0 {
            ops = append(ops, be)
        }
        if be.kind != 3 {
            continue
        }
        label++
        ls := labelStr(label)
        fmt.Printf("    %s = %s %s %s\n", ls, be.left, be.op, be.right)
        for j := i - 1; j > last; j-- {
            be2 := binexps[j]
            if be2.kind == 2 {
                label++
                ls2 := labelStr(label)
                fmt.Printf("    %s = %s %s %s\n", ls2, ls, be2.op, be2.right)
                ls = ls2
                be = be2
            } else if be2.kind == 1 {
                label++
                ls2 := labelStr(label)
                fmt.Printf("    %s = %s %s %s\n", ls2, be2.left, be2.op, ls)
                ls = ls2
                be = be2
            }
        }
        args = append(args, be)
        labels = append(labels, ls)
        lea, leo := len(args), len(ops)
        for lea >= 2 {
            if i < len(binexps)-1 && args[lea-2].index <= ops[leo-1].index {
                break
            }
            label++
            ls2 := labelStr(label)
            fmt.Printf("    %s = %s %s %s\n", ls2, labels[lea-2], ops[leo-1].op, labels[lea-1])
            ops = ops[0 : leo-1]
            args = args[0 : lea-1]
            labels = labels[0 : lea-1]
            lea--
            leo--
            args[lea-1] = be
            labels[lea-1] = ls2
        }
        last = i
    }
}