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

noitalmost <noitalmost@cox.net>
Fri, 21 Mar 2014 14:49:23 -0400

          From comp.compilers

Related articles
Trouble implementing a standard library -- Calling C functions from wi noitalmost@cox.net (noitalmost) (2014-03-19)
Re: Trouble implementing a standard library -- Calling C functions fro DrDiettrich1@aol.com (Hans-Peter Diettrich) (2014-03-20)
Re: Trouble implementing a standard library -- Calling C functions fro alexfrunews@gmail.com (2014-03-19)
Re: Trouble implementing a standard library -- Calling C functions fro noitalmost@cox.net (noitalmost) (2014-03-21)
| List of all articles for this month |

From: noitalmost <noitalmost@cox.net>
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 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<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.