Home-Produkte-Testarea-Kontakt-Datenschutz-Aktualisiert: 06-Aug-2009
< Voriger Tag   Nächster Tag >

Donnerstag, 06. August 2009

Lx0: Prototyp -- Klasse

Die Deklaration von Klassen und der Aufruf von Methoden sind im Prototyp meiner Programmiersprache Lx0 hinzugekommen. Womit nun folgendes funktioniert:

public class MyCounter extends Root
    private uword $count;
    private uword $mycount;


    public foo()
        helloworld;
    end foo

    public bar(ubyte $dip)
        print $dip;
    end bar
endclass MyCounter


MyCounter $obj;
$obj := new MyCounter();
$obj.foo();
$obj.bar(42);

Der für die Klassen generierte Programmcode entspricht dem in OOP in C beschriebenen.

Im Compiler ist für die Verarbeitung der Klassen und insbesonders der Codegenerierung der zwei Dateien pro Klasse (.h- und .c-Datei) einiges hinzugekommen.

.c und .h

Zur Generierung der .h- und .c-Datei einer Klasse wird der AST zweimal durchlaufen. Einmal mit den C_h.stg- und ein zweites Mal mit den C_c.stg-Templates. Diese Templategruppen erben alle Templates aus C.stg und fügen weitere hinzu. Die Vererbung geschieht mit group C_h: C;

group C_h: C;

class(modifier,name,extends,attrs,methodsPointer,methodsDecl) ::= <<
#ifndef _<name; format="toUpper">_CLASS_H
#define _<name; format="toUpper">_CLASS_H

#ifdef	__cplusplus
extern "C" {
#endif

    typedef struct <name>_Attributes {
        struct <name>_Methods *vtable;

        <attrs; separator="\n">
    } <name; format="toUpper">;


    typedef struct <name>_Methods {
        void *super; // vtable of super class
        char *classname;
        void (*constructor) (<name; format="toUpper"> *this);
        <methodsPointer; separator="\n">
    } <name>_Methods;


    void <name>_constructor(<name; format="toUpper"> *this);
    <methodsDecl; separator="\n">

    extern <name>_Methods <name>_vtable;

#ifdef	__cplusplus
}
#endif

#endif /* <name; format="toUpper"> */

>>


attrDecl(type,id) ::= <<
<type> <id>;
>>


methodDeclPointer(classname,name,pars,block) ::= <<
void (*<name>) (<classname; format="toUpper"> *this<if(pars)>, <pars; separator=", "><endif>);
>>

methodDecl(classname,name,pars,block) ::= <<
void <classname>_<name>(<classname; format="toUpper"> *this<if(pars)>, <pars; separator=", "><endif>);
>>

Die so generierten Quelltexte werden in public List<ClassSource> classes = new ArrayList<ClassSource>(); vom Treewalker gesammelt und innerhalb von Compiler.java auf die Festplatte geschrieben:

// .h file
TreeWalker walker = new TreeWalker(nodes);
walker.setTemplateLib(templates_h);
String csrc =  walker.program().toString();
if(walker.errors > 0) {
    System.err.println(walker.errors + " error(s).");
    System.exit(1);
}

for(ClassSource cs: walker.classes) {
    System.out.println(cs.name);
    //System.out.println(cs.source.toString());

    // Write .h file
    writeFile(cs.name + "_class.h", cs.source.toString());
}

Eine Alternative zu 2 Templates ist die Nutzung einer if-Abfrage innerhalb eines Templates:

methodDecl(classname,name,pars,block,isPointer) ::= <<
<if(isPointer)>
...
<else>
...
<endif>
>>

methodDeclPointer() und methodDecl()

Eine zweite Besonderheit ist, dass auch pro Methode jeweils zwei unterschiedliche Quelltexte in der .h-Datei generiert werden müssen. Aus

public foo()
    helloworld;
end foo

wird wird die .h-Datei:

typedef struct MyCounter_Methods {
    void *super; // vtable of super class
    char *classname;
    void (*constructor) (MYCOUNTER *this);
    void (*foo) (MYCOUNTER *this);
    void (*bar) (MYCOUNTER *this, unsigned char dip);
} MyCounter_Methods;


void MyCounter_constructor(MYCOUNTER *this);
void MyCounter_foo(MYCOUNTER *this);
void MyCounter_bar(MYCOUNTER *this, unsigned char dip);

Dies wird mit den zwei Templates methodDeclPointer() und methodDecl() gelöst. Da ANTLR meines Wissens darauf ausgelegt ist im Treewalker nur ein Template pro Regel zu benutzen, wird das zweite Template per direkten Aufruf von templateLib.getInstanceOf("methodDeclPointer", ... benutzt und als zusätzlicher Rückgabewert angegeben: Treewalker.g

methodDecl returns [StringTemplate methodPointer]
    : ^(modifier nameBegin=METHODNAME

[...]

         $methodPointer = templateLib.getInstanceOf("methodDeclPointer",
             new STAttrMap().put("classname", $classDecl::classname)
                            .put("name", $nameBegin.text)
                            .put("pars", $pars)
                            .put("block", $block.st));
        }
        -> methodDecl(classname={$classDecl::classname},name={$nameBegin.text},pars={$pars},block={$block.st})
     ;

format="toUpper" für den Klassennamen

An einigen Stellen wird der Klassenname ClassName durchgehend in Großbuchstaben benötigt CLASSNAME. Dies ist mit dem AttributeRenderer von StringTemplate umgesetzt. Innerhalb der Templates steht:

<classname; format="toUpper"> 

Damit das toUpper eine Funktion erhält muss es in einem eigenen AttributeRenderer definiert und dieser Renderer für die String-Klasse registriert werden. Beides geschieht in Compiler.java:

class TemplateFormatRenderer implements AttributeRenderer {

    public String toString(Object o) {
        return o.toString();
    }

    public String toString(Object o, String formatName) {
        if (formatName.equals("toUpper")) {
            return o.toString().toUpperCase();
        } else {
            throw new IllegalArgumentException("Unsupported format name");
        }
    }
}

[...]

templates.registerRenderer(String.class, new TemplateFormatRenderer());

Als nächstes: Aufbau des Lx0-Compilers

Im Zusammenhang mit Klassen fehlt noch einiges:

  • Vererbung
  • Typüberprüfung beim Methodenaufruf
  • Konstruktor deklarieren und aufrufen
  • Destruktor
  • Eigenschaften lesen/setzen
  • Symbole aus Klassen anderer Quelltexte einlesen
  • private, public verarbeiten
  • lx0lib.a

Bevor das umgesetzt wird, macht es jetzt erst einmal Sinn zu überlegen wie der Compiler im Ganzen aufgebaut ist und die Klassen, Typen, generierten Quelltexte, ... verwaltet werden, um einen Compiler zu ergeben, der aus vielen einzelnen Lx0-Quelltexten die passenden C-Quelltexte für ein ausführbares Programm erzeugt.

Quelltext

Der komplette Quelltext des Lx0-Compilers steht in Subversion.

[Direktlink]

< Voriger Tag   Nächster Tag >

  RSS V0.91

<August 2009 >
     0102
03040506070809
10111213141516
17181920212223
24252627282930
31      

Home-Produkte-Testarea-Kontakt-Datenschutz-Aktualisiert: 06-Aug-2009
(C) 2000-2018 by Sven Drieling