Re: Trouble implementing a standard library -- Calling C functions from within my language

noitalmost <>
Fri, 21 Mar 2014 14:49:23 -0400

          From comp.compilers

Related articles
Trouble implementing a standard library -- Calling C functions from wi (noitalmost) (2014-03-19)
Re: Trouble implementing a standard library -- Calling C functions fro (Hans-Peter Diettrich) (2014-03-20)
Re: Trouble implementing a standard library -- Calling C functions fro (2014-03-19)
Re: Trouble implementing a standard library -- Calling C functions fro (noitalmost) (2014-03-21)
| List of all articles for this month |

From: noitalmost <>
Newsgroups: comp.compilers
Date: Fri, 21 Mar 2014 14:49:23 -0400
Organization: Compilers Central
References: 14-03-049 <fqWX1n00a1AptjU01qWZHX>
Keywords: C, code
Posted-Date: 22 Mar 2014 00:19:41 EDT

On Thursday, March 20, 2014 12:41:16 AM 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

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<Expr*> 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<AstNode*> 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. :[

Post a followup to this message

Return to the comp.compilers page.
Search the comp.compilers archives again.