Пример #1
0
int main(int argc, char** argv)
{
	//argc == 2 --> only the source file is given
	//argc == 4 --> source file and target C file is given
	if (argc != 2 && argc != 4) { //only 2 and 4 is accepted
		print_usage(argv[0]);
		return -1;
		//if the output file is given, flag must be -o
	} else if (argc == 4 && std::string(argv[2]) != "-o") {
		std::cout << "Error: Output file must be given after -o flag"
			<< std::endl;
		return -2;
	}
	//argc == 2 or argc == 4
	const std::string Source_name = argv[1];
	const std::string Default_output_name = strip_extensions(Source_name) +".c";
	// if we have only one cmd argument, produce a result with a default name.
	const std::string Output_name = (argc == 2) ? Default_output_name : argv[3];
	//preprocessor strips comments from the file without deleting any line
	//this way, line numbers are preserved
	Preprocessor pp;
	const std::string Preprocessed_name = pp.remove_comments(Source_name);
	//we work on the preprocessed file
	std::ifstream source_file(Preprocessed_name.c_str());
	if (!source_file) {
		std::cout << Preprocessed_name << " couldn't be opened" << std::endl;
		return -3;
	}
	SymbolTable sym_table;
	Lexer lexer; //lexer tokenizes the source file
	Parser parser(&sym_table); //parser does the syntax check
	SemanticAnalyzer sem_analyze(&sym_table); //semantic checks
	//generates the code. Does semantic checks on expressions
	CodeGenerator code_gen(&sym_table);
	std::string line; //holds the current line
	int line_count = 0;
	//stores the whole file as lines. Each line is a vector of tokens and a
	//statement type and the line number. See definitions.hpp for more info
	std::vector<stmt_with_info> source_as_tokens;
	Regex empty_line_rgx(R"(^[[:space:]]*$)");
	while (std::getline(source_file, line)) {
		++line_count;
		//whenever we see an empty line, we go to the next line
		if (!empty_line_rgx.search(line)) {
			try {
				//tokenize the current line
				auto token_vec = lexer.tokenize(line);
				if (token_vec.empty()) {
					continue;
				}
				//parser does syntax check on the token vector and returns
				//what kind of statement this particular token vector is
				auto stmt_category = parser.parse(token_vec);
				source_as_tokens.emplace_back(token_vec, stmt_category, line_count);
			} catch (std::runtime_error e) {
				//embed line info to the error and quit the program
				//no file is generated up to this point. Thus, no extra cleanup
				std::cout << "Error (Line " << line_count << "): " <<
					e.what() << std::endl;
				return -4;
			}