bool QueryEvaluator::evaluatePTClause(TNode * PT_node, 
										vector<int> row, 
										vector<vector<int>> * new_rows, 
										ResultTable * temp_result) {
	TNode * stmt_node = PT_node->getChildAtIndex(0);
	string stmt_name = stmt_node->getValue();
	Symbol stmt_type = SyntaxHelper::getSymbolType(table.getType(stmt_name));
	int stmt_index=row[0]; // get stmt_index from row

	if (stmt_index==-1) {
		// retrieve a list of values of stmt_type from PKB
		vector<int> stmt_indexes = getAllPKBValues(stmt_name);
		for (size_t i=0; i<stmt_indexes.size(); i++) {
			//save back stmt_indexes[i] to row
			row[0] = stmt_indexes[i];
			//recursive call to update new_rows
			vector<vector<int>> rows;
			bool isSatisfied = evaluatePTClause(PT_node, row, &rows, temp_result);
			if (isSatisfied) {
				for (size_t j=0; j<rows.size(); j++) {
					new_rows->push_back(rows[j]);
				}
			}
		}
	} else {
		// from here is hell of logic
		// get ASTNode of this Stmt
		TNode * root = PKB::getASTRoot();
		AST tree; tree.setRoot(root);
		TNode * ast_node = tree.findNodeOfStmt(stmt_index);
	
		// handle first argument node
		TNode * arg1_node = stmt_node->getChildAtIndex(0);
		if (!evaluatePTArgNode(arg1_node, ast_node, ARG1, row, new_rows)) 
			return false; 

		switch(stmt_type) {
		case Assign:
			{
				TNode * expr_node = stmt_node->getChildAtIndex(1);
				if (!evaluateExprNode(expr_node, ast_node)) return false;
				return true;
			}
		case While:
			{

				break;
			}
		case If:
			{

				break;
			}
		default:
			break;
		}
	}
	if (!new_rows->empty()) return true;
	return false;
}
Example #2
0
/// Read-Eval-Print-Loop
static void repl(CEnv& cenv, ExecutionEngine* engine)
{
	while (1) {
		std::cout << "> ";
		std::cout.flush();
		SExp exp = readExpression(std::cin);

		try {
			AST* ast = parseExpression(exp);
			if (ast->evaluatable()) {
				ASTPrototype* proto = new ASTPrototype(false, "", vector<string>());
				ASTFunction*  func  = new ASTFunction(proto, ast);
				Function*     code  = func->Funcgen(cenv);
				void*         fp    = engine->getPointerToFunction(code);
				double (*f)() = (double (*)())fp;
				std::cout << f() << endl;
			} else {
				Value* code = ast->Codegen(cenv); 
				std::cout << "Generated code:" << endl;
				code->dump();
			}
		} catch (SyntaxError e) {
			std::cerr << "Syntax error: " << e.what() << endl;
		}
	}
}
Example #3
0
int __etest(const char *program)
{
	FILE *f = fopen("/tmp/tmp", "w");
	if (f == NULL) {
		//fprintf(stderr, "open fail %s (%s)\n", strerror(errno), argv[1]);
		exit(-1);
	}
	fwrite(program, 1, strlen(program), f);
	fclose(f);

	SCParser parser;
	AST *ast = parser.parse("/tmp/tmp");

	assert(ast);

	DBG("%s", ast->toString().c_str());
	DBG("\n");
	DBG("%s", ast->toSource().c_str());

	TypeCheck typeCheck;
	ast->accept(&typeCheck);

	DBG("%s\n", SymbolTable.toString().c_str());

	int err = typeCheck.getLastError();
	return err;
}
Example #4
0
void DepGenerator::analyse(const AST& ast) {
    const string& modName = ast.getModuleName();
    const string& fileName = ast.getFileName();

    ModInfo* info = getInfo(modName);
    info->addFile(fileName, ast);
}
Example #5
0
int main() {

	

	AST *ast = new ASTree();
	ast->ShowTree();

	//ast.GetCurrentElement()
}
Example #6
0
AST*
ASTHelper::retrieveMethodAST( IPosition<SourceToken>& p )
{
	AST* ast = this->ast.copySubtree( p );

	ast->storeIndent();
	
	return ast;
}
Example #7
0
void testFile(const char *file)
{
	SCParser parser;
	AST *ast = parser.parse(file);
	if (ast) {
		DBG("%s", ast->toString().c_str());
		DBG("\n");
		DBG("%s", ast->toSource().c_str());
	}
}
Example #8
0
int main ()
{

  AST* id = new ID_NODE("may_var");
  AST* val = new VAL_NODE(5.5);
  AST* opr = new OPR_NODE('+', id, val);
  opr->process();
  return 0;



}
Example #9
0
	void MittenSource::onNode(AST &a, ASTBuilder &b, ErrorHandler &e, StructureParser &p)
	{
		MittenErrorHandler &meh = dynamic_cast<MittenErrorHandler &>(e);

		if (a.isBranch() && a.name().compare("line") == 0)
		{
			cout << "LINE: " << a.display() << "\n";

			if (a.size() == 2)
			{
				if (a[0].isLeaf() && a[0].leaf().value().compare("include") == 0)
				{
					if (a[1].isBranch())
					{
						if (a[1].size() == 1)
						{
							if (a[1][0].size() == 1)
							{
								if (a[1][0][0].isLeaf())
								{
									Token inc = a[1][0][0].leaf();
									if (inc.tag() == SymbolTag)
										cout << "INCLUDE MODULE '" << inc.value() << "'\n";
									else if (inc.tag() == StringLiteralTag)
										cout << "INCLUDE FILE '" << inc.value() << "'\n";
									else
										meh.includeRequiresModuleOrFileName(a[0].leaf());
								}
								else
								{
									meh.includeRequiresModuleOrFileName(a[0].leaf());
								}
							}
							else
							{
								meh.includeRequiresOneArgument(a[0].leaf());
							}
						}
						else
						{
							meh.includeRequiresOneArgument(a[0].leaf());
						}
					}
					else
					{
						meh.includeRequiresArgumentList(a[0].leaf());
					}
				}
			}
		}
	}
Example #10
0
int Calculator::eval(string expr, bool flag) {

  Parser* parser = new Parser(new istringstream(expr), flag);
   
   AST* tree = parser->parse();
   
   int result = tree->evaluate();
   
   delete tree;
   
   delete parser;
   
   return result;
}
Example #11
0
void testFile(const char *file)
{
	SCParser parser;

	AST *ast = parser.parse(file);
	if (ast) {
		DBG("%s", ast->toString().c_str());
		DBG("\n");
		DBG("%s", ast->toSource().c_str());
	}
	TypeCheck typeCheck;
	ast->accept(&typeCheck);
	//int err = typeCheck.getLastError();
}
Example #12
0
File: cfg.cpp Project: cmj0121/Zerg
size_t CFG::_varcnt_(void) {
	size_t cnt = 0;

	for (ssize_t i = 0; i < this->length(); ++i) {
		AST *child = (AST *)this->child(i);

		switch(child->type()) {
			case AST_ASSIGN:
				if (0 != child->length() && 0 == child->child(0)->length()) {
					cnt ++;
				}
				break;
			case AST_FUNC:
				if (0 != child->length() && 0 != child->child(0)->length()) {
					cnt += child->child(0)->child(0)->length();
				}
				break;
			default:
				_D(LOG_DEBUG, "Need NOT count on %s", child->data().c_str());
				break;
		}
	}

	cnt += (NULL == this->nextCFG(true)  ? 0 : this->nextCFG(true)->_varcnt_());
	cnt += (NULL == this->nextCFG(false) ? 0 : this->nextCFG(false)->_varcnt_());

	return cnt;
}
Example #13
0
void scopeOfNode( AST* ast, QStringList& scope )
{
    if( !ast )
        return;

    if( ast->parent() )
        scopeOfNode( ast->parent(), scope );

    QString s;
    switch( ast->nodeType() )
    {
    case NodeType_ClassSpecifier:
        if( ((ClassSpecifierAST*)ast)->name() ){
            s = ((ClassSpecifierAST*)ast)->name()->text();
            s = s.isEmpty() ? QString::fromLatin1("<unnamed>") : s;
            scope.push_back( s );
        }
        break;

    case NodeType_Namespace:
    {
        AST* namespaceName = ((NamespaceAST*)ast)->namespaceName();
        s = namespaceName ? namespaceName->text() : QString::fromLatin1("<unnamed>");
        scope.push_back( s );
    }
    break;

    case NodeType_FunctionDefinition:
    {
        FunctionDefinitionAST* funDef = static_cast<FunctionDefinitionAST*>( ast );
        DeclaratorAST* d = funDef->initDeclarator()->declarator();

        // hotfix for bug #68726
        if ( !d->declaratorId() )
            break;

        QList<ClassOrNamespaceNameAST*> l = d->declaratorId()->classOrNamespaceNameList();
        for( int i = 0; i < l.size(); ++i ) {
            AST* name = l.at(i)->name();
            scope.push_back( name->text() );
        }
    }
    break;

    default:
        break;
    }
}
Example #14
0
int main()
{
    Parser parser;
    parser.parse();
    AST ast = parser.ast();

    if (ast.printErrors(std::cerr))
        return -1;

    int code = SymbolResolver::resolve(ast, std::cerr);
    if (code)
        return code;

    PrintVisitor::print(std::cerr, ast);
    PrintCode::print(std::cout, ast, true);
}
Example #15
0
C2Sema::C2Sema(SourceManager& sm_, DiagnosticsEngine& Diags_, AST& ast_, clang::Preprocessor& PP_)
    : SourceMgr(sm_)
    , Diags(Diags_)
    , typeContext(ast_.getTypeContext())
    , ast(ast_)
    , PP(PP_)
{}
Example #16
0
bool C2Builder::checkModuleImports(ParseHelper& helper, Component* component, Module* module, ImportsQueue& queue, const LibInfo* lib) {
    if (!module->isLoaded()) {
        assert(lib);
        if (options.verbose) log(COL_VERBOSE, "parsing (%s) %s", component->getName().c_str(), lib->c2file.c_str());
        if (!helper.parse(*component, module, lib->c2file, (options.printAST0 && options.printASTLib))) {
            return false;
        }
    }
    if (options.verbose) log(COL_VERBOSE, "checking imports for module (%s) %s", component->getName().c_str(), module->getName().c_str());
    bool ok = true;
    const AstList& files = module->getFiles();
    for (unsigned a=0; a<files.size(); a++) {
        AST* ast = files[a];
        for (unsigned u=1; u<ast->numImports(); u++) {  // NOTE: first import is module decl
            ImportDecl* D = ast->getImport(u);
            const std::string& targetModuleName = D->getModuleName();
            // handle c2 pseudo-module
            if (targetModuleName == "c2") {
                createC2Module();
                D->setModule(c2Mod);
                continue;
            }
            const LibInfo* target = libLoader.findModuleLib(targetModuleName);
            if (!target) {
                helper.Diags.Report(D->getLocation(), clang::diag::err_unknown_module) << targetModuleName;
                ok = false;
                continue;
            }
            D->setModule(target->module);
            if (target->component != component) {
                // check that imports are in directly dependent component (no indirect component)
                if (!component->hasDep(target->component)) {
                    helper.Diags.Report(D->getLocation(), clang::diag::err_indirect_component)
                            << component->getName() << target->component->getName() << targetModuleName;
                    ok = false;
                    continue;
                }
            }

            if (target->module->isLoaded()) continue;
            queue.push_back(targetModuleName);
        }
    }
    return ok;
}
QList<CppQuickFixOperation::Ptr> CompleteSwitchCaseStatement::match(
    const QSharedPointer<const CppEditor::Internal::CppQuickFixAssistInterface> &interface)
{
    const QList<AST *> &path = interface->path();

    if (path.isEmpty())
        return noResult(); // nothing to do

    // look for switch statement
    for (int depth = path.size() - 1; depth >= 0; --depth) {
        AST *ast = path.at(depth);
        SwitchStatementAST *switchStatement = ast->asSwitchStatement();
        if (switchStatement) {
            if (!interface->isCursorOn(switchStatement->switch_token) || !switchStatement->statement)
                return noResult();
            CompoundStatementAST *compoundStatement = switchStatement->statement->asCompoundStatement();
            if (!compoundStatement) // we ignore pathologic case "switch (t) case A: ;"
                return noResult();
            // look if the condition's type is an enum
            if (Enum *e = conditionEnum(interface, switchStatement)) {
                // check the possible enum values
                QStringList values;
                Overview prettyPrint;
                for (unsigned i = 0; i < e->memberCount(); ++i) {
                    if (Declaration *decl = e->memberAt(i)->asDeclaration()) {
                        values << prettyPrint(LookupContext::fullyQualifiedName(decl));
                    }
                }
                // Get the used values
                Block *block = switchStatement->symbol;
                CaseStatementCollector caseValues(interface->semanticInfo().doc, interface->snapshot(),
                                                  interface->semanticInfo().doc->scopeAt(block->line(), block->column()));
                QStringList usedValues = caseValues(switchStatement);
                // save the values that would be added
                foreach (const QString &usedValue, usedValues)
                    values.removeAll(usedValue);
                if (values.isEmpty())
                    return noResult();
                else
                    return singleResult(new Operation(interface, depth, compoundStatement, values));
            }

            return noResult();
        }
    }
Example #18
0
template <typename T> T* BuildASTVisitor::stackPop()
{
    if( aststack.isEmpty() )
    {
        kDebug(9024) << kBacktrace();
        kFatal(9024) << "ERROR: AST stack is empty, this should never happen";
        exit(255);
    }
    AST* tmp = aststack.pop();
    T* ast = dynamic_cast<T*>(tmp);
    if( !ast )
    {
        kDebug(9024) << kBacktrace();
        kFatal(9024) << "ERROR: AST stack is screwed, doing a hard exit" << tmp->type();
        exit(255);
    }
    return ast;
}
Example #19
0
PKB Parser::parseSource( string source ) {
	
	trim(source);

	addNewLineString(source);
	
	list<std::pair<int, string>> sourceCodeList;

	buildSourceCodeList(source, sourceCodeList);
	
	processSourceCodeList(sourceCodeList);
	cout << "end of everything before ast." << endl;
	AST ast = AST();
	ast.acceptStatements(sourceCodeList);
	pkb.setAST(ast);

	return pkb;
}
Example #20
0
Value* ASTIf::Codegen(CEnv& cenv)
{
	Value* condV = _cond->Codegen(cenv);

	// Convert condition to a bool by comparing equal to 0.0.
	condV = cenv.builder.CreateFCmpONE(
			condV, ConstantFP::get(APFloat(0.0)), "ifcond");

	Function* parent = cenv.builder.GetInsertBlock()->getParent();

	// Create blocks for the then and else cases.
	// Insert the 'then' block at the end of the function.
	BasicBlock* thenBB = BasicBlock::Create("then", parent);
	BasicBlock* elseBB = BasicBlock::Create("else");
	BasicBlock* mergeBB = BasicBlock::Create("ifcont");

	cenv.builder.CreateCondBr(condV, thenBB, elseBB);

	// Emit then value.
	cenv.builder.SetInsertPoint(thenBB);
	Value* thenV = _then->Codegen(cenv);

	cenv.builder.CreateBr(mergeBB);
	// Codegen of 'Then' can change the current block, update thenBB
	thenBB = cenv.builder.GetInsertBlock();

	// Emit else block.
	parent->getBasicBlockList().push_back(elseBB);
	cenv.builder.SetInsertPoint(elseBB);
	Value* elseV = _else->Codegen(cenv);

	cenv.builder.CreateBr(mergeBB);
	// Codegen of 'Else' can change the current block, update elseBB
	elseBB = cenv.builder.GetInsertBlock();

	// Emit merge block.
	parent->getBasicBlockList().push_back(mergeBB);
	cenv.builder.SetInsertPoint(mergeBB);
	PHINode* pn = cenv.builder.CreatePHI(Type::DoubleTy, "iftmp");

	pn->addIncoming(thenV, thenBB);
	pn->addIncoming(elseV, elseBB);
	return pn;
}
Example #21
0
void ParserTest::testMultipleProcedures()
{
	Parser p;
	std::string src;

	src =	"procedure main{\n"
			"	a = a + 2;}\n"
			"procedure text1{\n"
			"	b = a * (2 + c);\n"
			"	c = c - 2;}"
			"procedure text2{\n"
			"	while a{\n"
			"		d = d - 2;}\n"
			"	e = e + 1;\n"
			"	if a then {\n"
			"		h = h * (a * b);\n"
			"		b = b + 1;}\n"
			"	else{\n"
			"		c = b;\n"
			"		while z{\n"
			"			abc = xyz;\n"
			"			abc1 = xyz2 * xyz + h - y;}\n"
			"		a=abc1*2;}}";
			
	p.setSource(src);
	CPPUNIT_ASSERT_EQUAL(1, p.startParse());
	PKB *pkb = p.getPKB();
	
	// AST Test
	AST *ast = pkb->getRootAST();
	CPPUNIT_ASSERT(pkb->getType(ast->getRightSibling()) == PROCEDURE);
	CPPUNIT_ASSERT(pkb->getType(ast->getRightSibling()->getRightSibling()) == PROCEDURE);
	CPPUNIT_ASSERT(pkb->getType(ast->getRightSibling()->getRightSibling()->getFirstDescendant()->getFirstDescendant()) == WHILE);

	// Parent Test to ensure insertion is correct.
	CPPUNIT_ASSERT(!pkb->isParent(1, 9));
	CPPUNIT_ASSERT(pkb->isParent(4, 5));

	// Follow Test
	CPPUNIT_ASSERT(!pkb->isFollows(1, 2));
	CPPUNIT_ASSERT(!pkb->isFollows(3, 4));
	CPPUNIT_ASSERT(pkb->isFollows(4, 6));

}
Example #22
0
CodeGen hex(AST &ast){
	CodeGen cg;
	cg.generate(ast.get_root());
	cg.back_patch();
	cg.fill();
	// cg.print_hex();
	// cg.print_tables();

	return cg;
}
Example #23
0
void ASTTest::testAcrossMethods() {

	AST* asd = (AST::getInstance());
	CPPUNIT_ASSERT(asd->contains("Alice"));
	CPPUNIT_ASSERT(asd->contains("Bob"));

	ProcNode* pget = asd->getProcNode("Bob");
	CPPUNIT_ASSERT(NULL != pget);

	string expname = "Bob";
	CPPUNIT_ASSERT_EQUAL(expname, pget->getName());
	//CPPUNIT_ASSERT_EQUAL(pn, pget);

	StmtLstNode* sget = pget->getStmtLstNode();
	//CPPUNIT_ASSERT_EQUAL(sln, sget);
	string sname = "then";
	CPPUNIT_ASSERT_EQUAL(sname, sget->getName());

	return;
}
Example #24
0
void ASTTest::testInstances() {
	CPPUNIT_ASSERT(dynamic_cast<AST*>(ast));

	AST* asd = AST::getInstance();
	AST* qwe = AST::getInstance();

	CPPUNIT_ASSERT(asd->contains("Alice"));
	CPPUNIT_ASSERT(qwe->contains("Alice"));

	ProcNode* pn = new ProcNode("Bob");
	StmtLstNode* sln = new StmtLstNode("then");
	pn->linkStmtLstNode(sln);
	asd->addProcNode(pn);

	ProcNode* pget = asd->getProcNode("Bob");
	CPPUNIT_ASSERT(NULL != pget);

	string expname = "Bob";
	CPPUNIT_ASSERT_EQUAL(expname, pget->getName());
	CPPUNIT_ASSERT_EQUAL(pn, pget);

	StmtLstNode* sget = pget->getStmtLstNode();
	CPPUNIT_ASSERT_EQUAL(sln, sget);
	string sname = "then";
	CPPUNIT_ASSERT_EQUAL(sname, sget->getName());

	return;
}
Example #25
0
void P::parse_action(ASTBase **_root,int *_retsignal )
{
  zzRULE;
  int _signal=NoSignal;
  *_retsignal = NoSignal;
  loop_clause_nest_level = 0;
  *_root = new AST(TOK_STATEMENTS);

  tracein("action");

  while ( 1 )
    {
      statement( _root, &_signal );
      _signal = NoSignal;
      if ( LA(1) == Eof ) break;
    }

  ASTBase::tmake( NULL, (*_root)->bottom(), (new AST(Eof)) , NULL);
  if ( dumpflag && (*_root) )
    {
		((AST *)(*_root))->dumpTree("\nAST tree", ascii_buffer);
		printf("--------------------------------------------------\n");
		if (relocflag)
        {
          printf("Relocatable ASTs:\n");
          AST *look = ttr->getItemHead();
          while (look)
            {
              look->dumpNode("  ");
              look = look->getItemNext();
            }
          printf("--------------------------------------------------\n");
        }
    }

  traceout("action");
  return;
}
Example #26
0
AST* Parser::parse_case_branch(void) {
	AST* res = new AST();
	res->kind = AST_CASE_BRANCH;

	// Patron
	AST* pattern = parse_expression();
	if (!is_pattern(pattern)) {
		cerr << "Error en el case:" << endl;
		pattern->show(cerr, 1);
		cerr << endl;
		cerr << "no es un patron." << endl;
		exit(1);
	}
	res->children.push_back(pattern);

	assert_type(TOK_FAT_ARROW);
	_tokenizer.next();

	// Resultado
	res->children.push_back(parse_expression());
	
	return res;
}
// parent is either a FunctionDefinitionAST or a SimpleDeclarationAST
// line and column are 1-based
static bool findDeclOrDef(const Document::Ptr &doc, int line, int column,
                          DeclarationAST **parent, DeclaratorAST **decl,
                          FunctionDeclaratorAST **funcDecl)
{
    QList<AST *> path = ASTPath(doc)(line, column);

    // for function definitions, simply scan for FunctionDefinitionAST not preceded
    //    by CompoundStatement/CtorInitializer
    // for function declarations, look for SimpleDeclarations with a single Declarator
    //    with a FunctionDeclarator postfix
    FunctionDefinitionAST *funcDef = 0;
    SimpleDeclarationAST *simpleDecl = 0;
    *decl = 0;
    for (int i = path.size() - 1; i > 0; --i) {
        AST *ast = path.at(i);
        if (ast->asCompoundStatement() || ast->asCtorInitializer())
            break;
        if ((funcDef = ast->asFunctionDefinition()) != 0) {
            *parent = funcDef;
            *decl = funcDef->declarator;
            break;
        }
        if ((simpleDecl = ast->asSimpleDeclaration()) != 0) {
            *parent = simpleDecl;
            if (!simpleDecl->declarator_list || !simpleDecl->declarator_list->value)
                break;
            *decl = simpleDecl->declarator_list->value;
            break;
        }
    }
    if (!*parent || !*decl)
        return false;
    if (!(*decl)->postfix_declarator_list || !(*decl)->postfix_declarator_list->value)
        return false;
    *funcDecl = (*decl)->postfix_declarator_list->value->asFunctionDeclarator();
    return *funcDecl;
}
Example #28
0
void Error::complain(const AST &node, const char *fmt, ...)
{
    char buf[255] = { 0 };
    va_list list;
    // get compile source file path and name
    LocationMgr *locationMgr = getLocationMgr();
    string sourcePath = locationMgr->getCompileSourcePath();
    string sourceFile = locationMgr->getCompileSourceFile();
    int lineno = node.getLocation().getLineno();

    va_start(list, fmt);
    vsprintf(buf, fmt, list);
    std::cout << sourcePath << "/" << sourceFile << ":" << lineno << ":"  <<  buf << std::endl;
    va_end(list);
}
Example #29
0
void TagWriter::analyse(const AST& ast) {
    currentFile = getFile(ast.getFileName());

    for (unsigned i=0; i<ast.numTypes(); i++) {
        TagVisitor visitor(*this, ast.getType(i), SM);
        visitor.run();
    }
    for (unsigned i=0; i<ast.numVars(); i++) {
        TagVisitor visitor(*this, ast.getVar(i), SM);
        visitor.run();
    }
    for (unsigned i=0; i<ast.numFunctions(); i++) {
        TagVisitor visitor(*this, ast.getFunction(i), SM);
        visitor.run();
    }
    // TODO TypeDecls ArrayValueDecls
}
Example #30
0
void DepGenerator::writeAST(const AST& ast, StringBuilder& output, unsigned indent) const {
    if (showExternals) {
        for (unsigned i=0; i<ast.numImports(); i++) {
            const ImportDecl* U = ast.getImport(i);
            QualType Q = U->getType();
            const ModuleType* T = cast<ModuleType>(Q.getTypePtr());
            const Module* P = T->getModule();
            assert(P);
            if (P->isExternal()) addExternal(P);
        }
    }
    for (unsigned i=0; i<ast.numTypes(); i++) {
        writeDecl(ast.getType(i), output, indent);
    }
    for (unsigned i=0; i<ast.numVars(); i++) {
       writeDecl(ast.getVar(i), output, indent);
    }
    for (unsigned i=0; i<ast.numFunctions(); i++) {
        writeDecl(ast.getFunction(i), output, indent);
    }
}