示例#1
0
文件: Main.c 项目: Winter-M/Trot
int main(int argc, char **argv) {
	pt_node *node;
	if(argc < 2) {
		fprintf(stderr, "Argument required.\n");
		return -1;
	}

	node = buildAST(argv[1]);
	return visitRoot(node);
}
            void BoostSpiritGrammar::buildAST(const iter_t &it, ASTNode *parent, const uint32_t &depth) const {
                ASTNode *child = NULL;
                string key;
                for (uint32_t j = 0; j < it->children.size(); j++) {
                    string data((it->children.begin() + j)->value.begin(), (it->children.begin() + j)->value.end());
                    boost::algorithm::trim(data);
                    if ( (data != "") &&
                            ((it->children.begin() + j)->value.id().to_long() == 0) &&
                            ((it->children.begin() + j)->children.size() == 0)
                       ) {
                        // Keys have no children and an ID of 0 because they are keywords from the grammar.
                        key = data;
                        child = new ASTNode(parent);
                        child->setKey(key);
                        parent->addChild(child);
                    } else if ( (data != "") &&
                                ((it->children.begin() + j)->value.id().to_long() > 0) &&
                                ((it->children.begin() + j)->children.size() == 0) ) {
                        // Values have an ID greater than 0 and no children.
                        // Check if there's already a child with no value set.
                        if ( (child == NULL) || (child->getValue<string>() != "") ) {
                            child = new ASTNode(parent);
                            parent->addChild(child);
                        }
                        child->setKey(key);
                        child->setValue(data);
                    } else if ( ((it->children.begin() + j)->value.id().to_long() > 0) &&
                                ((it->children.begin() + j)->children.size() > 0) ) {
                        // Hierarchically sub-ordered values have also an ID greater than 0 but children as well.
                        ASTNode *multipleChildren = new ASTNode(parent);
                        buildAST(it->children.begin() + j, multipleChildren, depth + 1);
                        multipleChildren->setKey(key);
                        parent->addChild(multipleChildren);
//                        ASTNode *multipleChildren = NULL;
//                        if ( (parent != NULL) && (parent->getLastChild() != NULL) && (parent->getLastChild()->getKey() == key) && (parent->getLastChild()->getValue<string>() == "") ) {
//                            // Re-use last added child if value is empty AND keys are identical.
//                            multipleChildren = parent->getLastChild();
//                        }
//                        else {
//                            multipleChildren = new ASTNode(parent);
//                            parent->addChild(multipleChildren);
//                        }
//                        buildAST(it->children.begin() + j, multipleChildren, depth + 1);
//                        multipleChildren->setKey(key);
                    }
                }
            }
示例#3
0
ParsedAST TestTU::build() const {
  std::string FullFilename = testPath(Filename),
              FullHeaderName = testPath(HeaderFilename);
  std::vector<const char *> Cmd = {"clang", FullFilename.c_str()};
  // FIXME: this shouldn't need to be conditional, but it breaks a
  // GoToDefinition test for some reason (getMacroArgExpandedLocation fails).
  if (!HeaderCode.empty()) {
    Cmd.push_back("-include");
    Cmd.push_back(FullHeaderName.c_str());
  }
  Cmd.insert(Cmd.end(), ExtraArgs.begin(), ExtraArgs.end());
  ParseInputs Inputs;
  Inputs.CompileCommand.Filename = FullFilename;
  Inputs.CompileCommand.CommandLine = {Cmd.begin(), Cmd.end()};
  Inputs.CompileCommand.Directory = testRoot();
  Inputs.Contents = Code;
  Inputs.FS = buildTestFS({{FullFilename, Code}, {FullHeaderName, HeaderCode}});
  Inputs.Opts = ParseOptions();
  Inputs.Opts.ClangTidyOpts.Checks = ClangTidyChecks;
  Inputs.Index = ExternalIndex;
  if (Inputs.Index)
    Inputs.Opts.SuggestMissingIncludes = true;
  auto CI = buildCompilerInvocation(Inputs);
  assert(CI && "Failed to build compilation invocation.");
  auto Preamble =
      buildPreamble(FullFilename, *CI,
                    /*OldPreamble=*/nullptr,
                    /*OldCompileCommand=*/Inputs.CompileCommand, Inputs,
                    /*StoreInMemory=*/true, /*PreambleCallback=*/nullptr);
  auto AST = buildAST(FullFilename, createInvocationFromCommandLine(Cmd),
                      Inputs, Preamble);
  if (!AST.hasValue()) {
    ADD_FAILURE() << "Failed to build code:\n" << Code;
    llvm_unreachable("Failed to build TestTU!");
  }
  return std::move(*AST);
}
示例#4
0
int main(int argc, char *argv[])
{
	// Parse command line arguments.
	boost::filesystem::path output(".");
	if (argc >= 2) output = argv[1];

	// Create the output directory if required.
	if (!boost::filesystem::exists(output)) {
		cout << "Creating output directory " << output << '\n';
		boost::filesystem::create_directories(output);
	}

	// Build the AST.
	Builder builder;
	buildAST(builder);

	// Determine implemented interfaces and child nodes.
	determineImplementedInterfaces(builder);
	determineChildNodes(builder);

	// Generate the code for the nodes.
	Headers headerFileNames;
	Headers sourceFileNames;
	for (Builder::Nodes::iterator it = builder.nodes.begin(); it != builder.nodes.end(); it++) {
		const std::string &name = it->first;
		Node &node = it->second;
		//cout << "- Generating \033[36;1m" << name << "\033[0m" << '\n';
		std::string headerName = name + ".hpp";
		std::string sourceName = name + ".cpp";

		// Generate the header and source file.
		boost::filesystem::path hpath = output, spath = output;
		hpath /= headerName;
		spath /= sourceName;
		std::ofstream h(hpath.c_str());
		std::ofstream s(spath.c_str());

		h << "/* Automatically generated by ast-gen. DO NOT MODIFY. */\n";
		h << "#pragma once\n";
		h << "#include \"maxwell/ast/Node.hpp\"\n";
		h << "#include \"maxwell/ast/nodes/interfaces.hpp\"\n";
		h << "#include \"maxwell/ast/nodes/types.hpp\"\n";
		if (node.parent != "Node") h << "#include \"maxwell/ast/nodes/" << node.parent << ".hpp\"\n";
		h << '\n';

		s << "/* Automatically generated by ast-gen. DO NOT MODIFY. */\n";
		s << "#include \"maxwell/ast/nodes/" << headerName << "\"\n";
		s << "#include \"maxwell/ast/Coder.hpp\"\n";
		s << "#include <cstdio>\n";
		s << "#include <sstream>\n";
		s << "#include <stdexcept>\n";
		s << "using ast::" << name << ";\n";
		s << "using ast::NodePtr;\n";
		s << "using ast::NodeVector;\n\n";

		h << "namespace ast {\n\n";
		h << "class Encoder;\n";
		h << "class Decoder;\n\n";
		h << "class " << name << " : public Node\n{\npublic:\n";

		// Generate the constructor.
		h << "\t// constructor\n";
		h << "\t" << name << "();\n\n";
		s << name << "::" << name << "() : Node()";
		for (Node::Interfaces::iterator it = node.interfaces.begin(); it != node.interfaces.end(); it++) {
			const Node& intf = **it;
			s << ",\n\tinterface" << intf.name << "(this)";
		}
		s << " {}\n\n";

		// Generate auxiliary functions.
		h << "\t// auxiliary functions\n";
		h << "\tvirtual bool isKindOf(Kind k);\n";
		h << "\tvirtual bool implements(Interface i);\n";
		h << "\tvirtual std::string getClassName() const { return \"" << node.name << "\"; }\n";
		h << "\tvirtual NodePtr copy();\n";
		h << "\tvirtual bool equalTo(const NodePtr& o);\n";
		h << "\tvirtual std::string describe(int depth = -1);\n";
		h << '\n';

		// isKindOf
		s << "bool " << name << "::isKindOf(Kind k) {\n";
		s << "\tif (" << node.parent << "::isKindOf(k)) return true;\n";
		s << "\treturn k == k" << node.name << ";\n";
		s << "}\n\n";

		// implements
		s << "bool " << name << "::implements(Interface i) {\n";
		s << "\tif (" << node.parent << "::implements(i)) return true;\n";
		for (Node::Interfaces::iterator it = node.interfaces.begin(); it != node.interfaces.end(); it++) {
			const Node& intf = **it;
			s << "\tif (i == k" << intf.intfName << ") return true;\n";
		}
		s << "\treturn false;\n";
		s << "}\n\n";

		// copy
		s << "NodePtr " << name << "::copy() {\n";
		s << "\tPtr c (new " << name << ");\n";
		for (Node::Fields::iterator f = node.attributes.begin(); f != node.attributes.end(); f++) {
			s << "\tNode::copy(this->" << (*f).name << ", c->" << (*f).name << ");\n";
		}
		s << "\treturn c;\n";
		s << "}\n\n";

		// equalTo
		s << "bool " << name << "::equalTo(const NodePtr& o) {\n";
		s << "\tconst shared_ptr<" << node.name << ">& other = boost::dynamic_pointer_cast<" << node.name << ">(o);\n";
		s << "\tif (!other) return false;\n";
		for (Node::Fields::iterator fit = node.attributes.begin(); fit != node.attributes.end(); fit++) {
			Node::Field& f = *fit;
			s << "\tif (!equal(this->" << f.name << ", other->" << f.name << ")) return false;\n";
		}
		s << "\treturn true;\n";
		s << "}\n\n";

		// describe
		s << "std::string " << name << "::describe(int depth) {\n";
		s << "\tstd::stringstream str, b;\n";
		if (node.descriptionBody.empty()) {
			s << "\tif (depth == 0) return \"" << name << "{…}\";\n";
			s << "\tstr << \"" << name << "{\";\n";
			for (Node::Fields::iterator fit = node.attributes.begin(); fit != node.attributes.end(); fit++) {
				Node::Field& f = *fit;

				// Don't print empty strings and arrays.
				s << "\t";
				if (f.isString || f.isArray) s << "if (!this->" <<f.name<< ".empty()) ";
				if (f.isNode) s << "if (this->" << f.name << ") ";

				// Print the field name.
				s << "b << \"\\n  \\033[1m" << f.name << "\\033[0m = ";

				// Print the actual data.
				if (f.isString) s << "\\033[33m\\\"\" << this->" << f.name << " << \"\\\"\\033[0m\";";
				if (f.isBool) s << "\\033[34m\" << (this->" << f.name << " ? \"true\" : \"false\") << \"\\033[0m\";";
				if (f.isInt) s << "\\033[35m\" << this->" << f.name << " << \"\\033[0m\";";
				if (f.isNode) {
					if (f.ref) {
						s << "\\033[36m\" << this->" << f.name << ".id << \"\\033[0m\";";
					} else {
						s << "\" << indent(this->" << f.name << "->describe(depth-1));";
					}
				}
				if (f.isArray) s << "\" << indent(describeVector(this->" << f.name << ", depth-1));";
				s << "\n";
			}
			s << "\tstring bs = b.str();\n";
			s << "\tif (!bs.empty()) str << bs << '\\n';\n";
			s << "\tstr << \"}\";\n";
		} else {
			string body(node.descriptionBody);
			boost::algorithm::replace_all(body, "\n", "\n\t\t");
			s << "\t" << body << "\n";
		}
		s << "\treturn str.str();\n";
		s << "}\n\n";
		s << '\n';

		// Generate the accessor functions.
		h << "\t// accessor functions\n";
		for (Node::Fields::iterator fit = node.attributes.begin(); fit != node.attributes.end(); fit++) {
			Node::Field& f = *fit;
			string ref = "const " + f.cpp_type + "&";
			string upper = f.name;
			if (!upper.empty()) upper[0] = toupper(upper[0]);
			h << "\tvoid set" << upper << "(" << ref << " v);\n";
			s << "void " << name << "::set" << upper << "(" << ref << " v) {\n";

			vector<string> ifcomponents;
			string allowedNodes;
			string allowedInterfaces;
			for (unsigned i = 0; i < f.allowedNodes.size(); i++) {
				ifcomponents.push_back("!v->isKindOf(k" + f.allowedNodes[i] + ")");
				if (!allowedNodes.empty()) allowedNodes += ", ";
				allowedNodes += f.allowedNodes[i];
			}
			for (unsigned i = 0; i < f.allowedInterfaces.size(); i++) {
				ifcomponents.push_back("!v->implements(k" + builder.interfaces[f.allowedInterfaces[i]].intfName + ")");
				if (!allowedInterfaces.empty()) allowedInterfaces += ", ";
				allowedInterfaces += f.allowedInterfaces[i];
			}
			if (!ifcomponents.empty()) {
				s << "\tif (v";
				for (unsigned i = 0; i < ifcomponents.size(); i++) {
					s << " && " << ifcomponents[i];
				}
				s << ") {\n";
				s << "\t\tthrow std::runtime_error(\"'" << f.name << "' of \" + id.str() + \" needs to be of kind {" << allowedNodes << "} or implement interface {" << allowedInterfaces << "}, got \" + v->getClassName() + \" (\" + v->getId().str() + \") instead.\");\n";
				s << "\t}\n";
			}

			if (f.ref) {
				s << "\tif (!v && " << f.name << ") {\n";
				s << "\t\tmodify(\"" << f.name << "\");\n";
				s << "\t\t" << f.name << ".reset();\n";
				s << "\t}\n";
				s << "\tif (!" << f.name << " || v->getId() != " << f.name << ".id) {\n";
			} else {
				s << "\tif (!equal(v, " << f.name << ")) {\n";
			}
			s << "\t\tmodify(\"" << f.name << "\");\n";
			if (f.ref) {
				s << "\t\t" << f.name << ".set(v);\n";
			} else {
				s << "\t\t" << f.name << " = v;\n";
			}
			s << "\t}\n";
			s << "}\n\n";

			// special setter for references
			if (f.ref) {
				h << "\tvoid set" << upper << "(const NodeId& v);\n";
				s << "void " << name << "::set" << upper << "(const NodeId& v) {\n";
				s << "\tif (v != " << f.name << ".id) {\n";
				s << "\t\tmodify(\"" << f.name << "\");\n";
				s << "\t\t" << f.name << ".set(v);\n";
				s << "\t}\n";
				s << "}\n\n";
			}

			h << "\t" << ref << " get" << upper << "(bool required = true);\n\n";
			s << ref << " " << name << "::get" << upper << "(bool required) {\n";
			s << "\tconst " << f.cpp_type << "& v = ";
			if (f.ref) {
				s << f.name << ".get(repository);\n";
			} else {
				s << f.name << ";\n";
			}
			if (f.isNode) {
				s << "\tif (required && !v) {\n";
				s << "\t\tthrow std::runtime_error(\"Node \" + getId().str() + \" is required to have " << f.name << " set to a non-null value.\");\n";
				s << "\t}\n";
			} else if (f.isString) {
				s << "\tif (required && v.empty()) {\n";
				s << "\t\tthrow std::runtime_error(\"Node \" + getId().str() + \" is required to have a non-empty string " << f.name << " set.\");\n";
				s << "\t}\n";
			}
			s << "\treturn v;\n";
			s << "}\n\n\n";
		}

		// Generate the encode() and decode() function.
		h << "\t// encoding and decoding\n";
		h << "\tvirtual void encode(Encoder& e);\n";
		h << "\tvirtual void decode(Decoder& d);\n";
		h << '\n';

		s << "void " << name << "::encode(Encoder& e) {\n";
		s << "\te.encode(this->range);\n";
		s << "\te.encode(this->referenceRange);\n";
		for (Node::Fields::iterator f = node.attributes.begin(); f != node.attributes.end(); f++) {
			s << "\te.encode(this->" << (*f).name << ");\n";
		}
		s << "}\n\n";

		s << "void " << name << "::decode(Decoder& d) {\n";
		s << "\td.decode(this->range);\n";
		s << "\td.decode(this->referenceRange);\n";
		for (Node::Fields::iterator f = node.attributes.begin(); f != node.attributes.end(); f++) {
			s << "\td.decode(this->" << (*f).name << ");\n";
		}
		s << "}\n\n";
		s << '\n';

		// Generate the hierarchy functions.
		h << "\t// hierarchy functions\n";
		h << "\tvirtual void updateHierarchyOfChildren();\n";
		h << "\tvirtual const NodePtr& resolvePath(const std::string& path);\n";

		// updateHierarchy
		s << "void " << name << "::updateHierarchyOfChildren() {\n";
		for (Node::Fields::iterator fit = node.attributes.begin(); fit != node.attributes.end(); fit++) {
			Node::Field& f = *fit;
			if (f.isNode && !f.ref) {
				s << "\tif (this->"<<f.name<<") this->"<<f.name<<"->updateHierarchy(id + \""<<f.name<<"\", repository, this);\n";
			} else if (f.isNodeArray) {
				s << "\tfor (unsigned i = 0; i < this->"<<f.name<<".size(); i++) {\n";
				s << "\t\tchar buf[32]; snprintf(buf, 31, \"%i\", i);\n";
				s << "\t\tthis->"<<f.name<<"[i]->updateHierarchy((id + \""<<f.name<<"\") + buf, repository, this);\n";
				s << "\t}\n";
			}
		}
		s << "}\n\n";

		// resolvePath
		s << "const NodePtr& " << name << "::resolvePath(const std::string& path) {\n";
		FieldNames fields, arrayFields;
		for (Node::Fields::iterator fit = node.attributes.begin(); fit != node.attributes.end(); fit++) {
			Node::Field& f = *fit;
			if (f.isNode) {
				fields.insert(f.name);
			} else if (f.isNodeArray) {
				fields.insert(f.name);
				arrayFields.insert(f.name);
			}
		}
		if (!fields.empty()) {
			s << "\tsize_t size = path.size();\n";
			generateResolvePathBody(s, fields, arrayFields, 1);
		}
		s << "\tthrow std::runtime_error(\"Node path '\" + path + \"' does not point to a node or array of nodes.\");\n";
		s << "}\n\n";

		// getChildren
		if (!node.children.empty()) {
			h << "\tvirtual NodeVector getChildren();\n";
			s << "NodeVector " << name << "::getChildren() {\n";
			s << "\tNodeVector v;\n";
			for (Node::Children::iterator c = node.children.begin(); c != node.children.end(); c++) {
				Node::Field& f = **c;
				if (f.isNode) {
					string upper = (char)toupper(f.name[0]) + f.name.substr(1);
					s << "\tif (const NodePtr& n = this->get" << upper << "(false)) v.push_back(n);\n";
				} else if (f.isArray) {
					s << "\tv.insert(v.end(), this->" << f.name << ".begin(), this->" << f.name << ".end());\n";
				}
			}
			s << "\treturn v;\n";
			s << "}\n\n";
		}
		h << '\n';

		// Generate the interface accessors.
		if (!node.interfaces.empty()) {
			h << "\t// interfaces\n";
			for (Node::Interfaces::iterator it = node.interfaces.begin(); it != node.interfaces.end(); it++) {
				const Node& intf = **it;
				h << "\tvirtual " << intf.intfName << "* as" << intf.name << "() { return &this->interface" << intf.name << "; }\n";
			}
			h << "\n";
		}

		// Generate boost::shared_ptr convenience typedef.
		h << "\t// shared_ptr convenience\n";
		h << "\ttypedef boost::shared_ptr<" << node.name << "> Ptr;\n";
		h << "\ttemplate<typename T> static Ptr from(const T& n) { return boost::dynamic_pointer_cast<" << node.name << ">(n); }\n";
		h << "\ttemplate<typename T> static Ptr needFrom(const T& n) {\n";
		h << "\t\tPtr r = boost::dynamic_pointer_cast<" << node.name << ">(n);\n";
		h << "\t\tif (!r)\n";
		h << "\t\t\tthrow std::runtime_error(\"Node \" + n->getId().str() + \" (a \" + n->getClassName() + \") cannot be dynamically cast to " << node.name << ".\");\n";
		h << "\t\treturn r;\n";
		h << "\t}\n";
		h << '\n';

		h << "protected:\n";
		for (Node::Fields::iterator f = node.attributes.begin(); f != node.attributes.end(); f++) {
			if ((*f).ref) {
				h << "\tNodeRef " << (*f).name << ";\n";
			} else {
				h << "\t" << (*f).cpp_type << " " << (*f).name << ";\n";
			}
		}
		if (!node.interfaces.empty()) {
			h << "\n\t// interfaces\n";
			for (Node::Interfaces::iterator it = node.interfaces.begin(); it != node.interfaces.end(); it++) {
				const Node& intf = **it;
				h << "\t" << intf.intfName << "Impl<" << node.name << "> interface" << intf.name << ";\n";
			}
		}

		h << "};\n\n";
		h << "} // namespace ast\n";
		headerFileNames.push_back(headerName);
		sourceFileNames.push_back(sourceName);
	}

	// Generate the header file containing general typedefs.
	makeTypesHeader(output, builder);
	makeNodesHeader(output, builder, headerFileNames);
	makeInterfacesHeader(output, builder);

	// Generate the base header file for ast::Node which implements default interface accessors.
	makeBaseNodeHeader(output, builder);

	// Generate the header file aggregating all AST things.
	boost::filesystem::path ahpath = output;
	ahpath /= "ast.hpp";
	ofstream ah(ahpath.c_str());
	ah << "/* Automatically generated by ast-gen. DO NOT MODIFY. */\n";
	ah << "#pragma once\n\n";
	ah << "#include \"maxwell/ast/nodes/types.hpp\"\n";
	ah << "#include \"maxwell/ast/nodes/nodes.hpp\"\n";
	ah << "#include \"maxwell/ast/nodes/interfaces.hpp\"\n";

	return 0;
}