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

Sonntag, 12. April 2009

Java: Compilerbau mit ANTLR 3 und StringTemplate (2)

Im ersten Schritt konnte das Programm nur aus einen Befehl bestehen. Im zweiten soll dieser nun beliebig oft im Programm stehen dürfen.

helloworld;
helloworld;
helloworld;

HelloWorldStatementList.g

Hierzu werden die Befehle in einer Statementliste gesammelt und dann an das Template übergeben. Zu Deklaration von Variablen gibt es in ANTLR den scope{}-Block, dessen Inhalt direkt in den generierten Parser kopiert wird. In diesem Fall ist der scope{}-Block lokal zur program-Regel definiert, so dass innerhalb der ANTLR-Grammatik mit $program::statements auf die Liste zugegriffen wird.

Zur Initialisierung dient der @init{}-Block in dem mit $program::statements = new ArrayList(); die Liste initialisiert wird.

Die Kommentare aus diesen Blöcke werden in den Parsercode kopiert und stehen in Fall von ANTLR 3.1.3 in Zeile 60 und 79 von HelloWorldStatementListParser.java.

Die Syntax der Sprache ändert sich nur minimal. program : statement* erhält zusätzlichen den Stern '*'. Damit kann 'helloworld' nun null oder beliebig oft im Programmcode stehen. Und ans program()-Template wird die Liste der gesammelten Statements übergeben.

Das Sammeln der Befehle erfolgt in der statement-Regel durch das Anhängen des aktuellen Befehls per $program::statements.add($helloworld.st); an die Liste der Statements.

grammar HelloWorldStatementList;

options {output=template;}


program 
    scope {
        /* Statement list */
        List statements;
    }

    @init {
        /* Init statement list */
        $program::statements = new ArrayList();
    }

    : statement* EOF -> program(statements={$program::statements})
    ;

statement
    : helloworld ';' {$program::statements.add($helloworld.st);}
    ;

helloworld
    : 'helloworld' -> helloWorld()
    ;

WS  :   (' ' | '\t' | '\r' | '\n')+ {$channel=HIDDEN;}
    ;

Java.stg

Das program()-Template muss nun nicht nur einen Befehl, sondern alle Befehele ausgeben, die in der Statementliste stehen. Darum und um das Einrücken kümmert sich StringTemplate automatisch, so dass man in den Templates keine Schleife programmieren braucht, sondern nur den Namen plus das gewünschte Trennzeichen angibt: <statements; separator="\n">.

group Java;

program(statements) ::= <<
public class HelloWorld {
    public static void main(String[] args) {
        <statements; separator="\n">
    }
}
>>


helloWorld() ::= <<
System.out.println("Hello World!");
>>

C.stg

group C;

program(statements) ::= <<
#include \<stdio.h\>

int main(int argc, char *argv[]) {
    <statements; separator="\n">

    return 0;
}
>>


helloWorld() ::= <<
printf("Hello World!\\n");
>>

PHP.stg

group PHP;

program(statements) ::= <<
<statements; separator="\n">
>>


helloWorld() ::= <<
echo "Hello World!\\n";
>>

Main

Beim Hauptprogramm werden nur die Namen der Lexer- und Parser-Klasse angepasst.

import java.io.*;
import org.antlr.runtime.*;
import org.antlr.stringtemplate.*;
import org.antlr.stringtemplate.language.*;


public class Main {
    public static void main(String[] args)  {
        StringTemplateGroup templates;

        String templateFilename = "";
        String programFilename  = "";


        if(args.length < 2) {
            System.out.println("Main [template] [program]");
            System.exit(0);
        } else {
            templateFilename = args[0];
            programFilename  = args[1];
        }

        try {
            templates = new StringTemplateGroup(new FileReader(templateFilename),
                                                AngleBracketTemplateLexer.class);

            CharStream                    input  = new ANTLRFileStream(programFilename);
            HelloWorldStatementListLexer  lexer  = new HelloWorldStatementListLexer(input);
            CommonTokenStream             tokens = new CommonTokenStream(lexer);
            HelloWorldStatementListParser parser = new HelloWorldStatementListParser(tokens);

            parser.setTemplateLib(templates);
            RuleReturnScope r = parser.program();

            System.out.println(r.getTemplate().toString());

        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

Compilieren und ausführen

Anschließend wie im ersten Teil beschrieben compilieren und ausführen.

java org.antlr.Tool HelloWorldStatementList.g
javac Main.java HelloWorldStatementListLexer.java HelloWorldStatementListParser.java


> java Main Java.stg input

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World!");
        System.out.println("Hello World!");
        System.out.println("Hello World!");
    }
}


> java Main PHP.stg input

echo "Hello World!\n";
echo "Hello World!\n";
echo "Hello World!\n";

[Direktlink]

< Voriger Tag   Nächster Tag >

  RSS V0.91

<April 2009 >
  0102030405
06070809101112
13141516171819
20212223242526
27282930   

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