Path: csiph.com!v102.xanadu-bbs.net!xanadu-bbs.net!news.glorb.com!news-out.readnews.com!news-xxxfer.readnews.com!news.misty.com!news.iecc.com!.POSTED!nerds-end From: noitalmost Newsgroups: comp.compilers Subject: Re: Trouble implementing a standard library -- Calling C functions from within my language Date: Fri, 21 Mar 2014 14:49:23 -0400 Organization: Compilers Central Lines: 110 Sender: news@iecc.com Approved: comp.compilers@iecc.com Message-ID: <14-03-056@comp.compilers> References: <14-03-049@comp.compilers> NNTP-Posting-Host: news.iecc.com Mime-Version: 1.0 Content-Type: Text/Plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit X-Trace: miucha.iecc.com 1395461981 26909 2001:470:1f07:1126:0:676f:7373:6970 (22 Mar 2014 04:19:41 GMT) X-Complaints-To: abuse@iecc.com NNTP-Posting-Date: Sat, 22 Mar 2014 04:19:41 +0000 (UTC) Keywords: C, code Posted-Date: 22 Mar 2014 00:19:41 EDT X-submission-address: compilers@iecc.com X-moderator-address: compilers-request@iecc.com X-FAQ-and-archives: http://compilers.iecc.com Xref: csiph.com comp.compilers:1178 On Thursday, March 20, 2014 12:41:16 AM alexfrunews@gmail.com wrote: > In my C compiler I represent C types in a kind of AST that has them > deconvoluted and straightened out, e.g.: Yeah, maybe I should do something like that. I need to think about this some more. I don't think I quite know what I want. I think I need to rework my genC() methods so that they generate a C-like AST. > But if you're translating your language into compilable C, you need more > than just invoking a function. Where do you actually take function > parameters from? They must be C expressions, containing constants, > variables, other function calls and operators. > > Perhaps, you need to naturally generate C code out of all your expressions > and other building blocks of your source language? If each of them is > already parsed into a (sub)tree or a (sub)stack (e.g. containing the > expression in the Reverse Polish Notation, ready for evaluation or code > generation), it's not much of a problem and it's likely easier than doing > the same for the purpose of generating assembly code. The nodes of my AST are instances of C++ classes. Each node has a (virtual) genC() method that returns C source code as a string. It returns the code for itself and all its children. With a lot of details omitted, I have something like: class AstNode { virtual string genC(AstNode *parent); }; class Expr : public AstNode { string genC(AstNode *parent); }; class Call : public Expr { Call(string name); void addArg(Expr *arg); string genC(AstNode *parent); string m_name; // procedure name vector m_args; Type *m_retType; // type checker fills this in }; string Call::genC(AstNode *parent) { string s = m_name + "("; for (arg : m_args) s += arg->genC(this) + ", "; s += ")"; return s; } class SymDef : public AstNode { // a named symbol, which goes into a symbol table Type* dataType(); virtual string genCDecl(); }; string SymDef::genCDecl() { // return C declaration string s = dataType()->genC(this); s += " " + m_name; return s; // extra stuff to handle arrays has been omitted } class ProcDef : public SymDef { ProcDef(string name, Type *retType, SymTab *parent); void addParam(VarDef *p); SymDef* get(string name); string genC(AstNode *parent); SymTab m_symTab; vector m_stmts; }; string ProcDef::genC(AstNode *parent) { string s = m_retType->genC(this); s += " " + m_name + "("; for (p : params()) { // for each parameter s += p->dataType()->genC(this) + " "; s += p->genC(this) + ", "; } s += ") {\n"; for (decl : decls()) { // for each local declaration // excludes parameters s += decl->genCDecl(this) + ";\n"; } for (stmt : stmts()) { // for each statement s += stmt->genC(this) + ";\n"; } s += "}\n"; return s; } ProcDef is a procedure definition. It has a symbol table of local declarations (which includes the procedure parameters), and a list of statements. Each Type is also an AstNode. Int, Float, etc, are predeclared. Static instances for predeclared types are created at compile time and are in the global symbol table. string Type::genC(AstNode *parent) { if (this == &Int) return "long"; if (this == &Float) return "double"; } Array, Record, and Pointer derive from Type; Pointers essentially just add " *", while arrays and records become "char *". And I just found a bug in my code. I've ignored alignment of record fields in the translation to intermediate form. :[