Question

Je travaille sur un simple DSL de manipulation de chaînes à des fins internes, et je voudrais la langue pour soutenir l'interpolation de chaîne comme il est utilisé dans Ruby.

Par exemple:

name = "Bob"
msg = "Hello ${name}!"
print(msg)   # prints "Hello Bob!"

Je tente de mettre en œuvre mon analyseur en ANTLRv3, mais je suis assez inexpérimenté avec l'aide ANTLR je suis tellement sûr comment implémenter cette fonctionnalité. Jusqu'à présent, j'ai spécifié mes chaînes littérales dans le lexer, mais dans ce cas, je vais évidemment besoin de gérer le contenu d'interpolation dans l'analyseur.

Ma grammaire littérale actuelle chaîne ressemble à ceci:

STRINGLITERAL : '"' ( StringEscapeSeq | ~( '\\' | '"' | '\r' | '\n' ) )* '"' ;
fragment StringEscapeSeq : '\\' ( 't' | 'n' | 'r' | '"' | '\\' | '$' | ('0'..'9')) ;

Déplacement de la chaîne de manutention littérale dans l'analyseur semble tout faire d'autre arrêter de travailler comme il se doit. recherches sur le Web cursives n'a donné aucune information. Toutes les suggestions quant à la façon de commencer à ce sujet?

Était-ce utile?

La solution

Je ne suis pas expert en ANTLR, mais voici une grammaire possible:

grammar Str;

parse
    :    ((Space)* statement (Space)* ';')+ (Space)* EOF
    ;

statement
    :    print | assignment
    ;

print
    :    'print' '(' (Identifier | stringLiteral) ')' 
    ;

assignment
    :    Identifier (Space)* '=' (Space)* stringLiteral
    ;

stringLiteral
    :    '"' (Identifier | EscapeSequence | NormalChar | Space | Interpolation)* '"'
    ;

Interpolation
    :    '${' Identifier '}'
    ;

Identifier
    :    ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')*
    ;

EscapeSequence
    :    '\\' SpecialChar
    ;

SpecialChar
    :     '"' | '\\' | '$'
    ;

Space
    :    (' ' | '\t' | '\r' | '\n')
    ;

NormalChar
    :    ~SpecialChar
    ;

Comme vous le remarquez, il y a quelques (Space)*-es à l'intérieur de la grammaire par exemple. En effet, le stringLiteral est analyseur règle au lieu de Lexer règle . À cet effet, lorsque tokenizing le fichier source, le lexer ne peut pas savoir si un espace blanc fait partie d'une chaîne littérale, ou est juste un espace à l'intérieur du fichier source qui peut être ignoré.

Je l'ai testé l'exemple avec une classe peu Java et tout a fonctionné comme prévu:

/* the same grammar, but now with a bit of Java code in it */
grammar Str;

@parser::header {
    package antlrdemo;
    import java.util.HashMap;
}

@lexer::header {
    package antlrdemo;
}

@parser::members {
    HashMap<String, String> vars = new HashMap<String, String>();
}

parse
    :    ((Space)* statement (Space)* ';')+ (Space)* EOF
    ;

statement
    :    print | assignment
    ;

print
    :    'print' '(' 
         (    id=Identifier    {System.out.println("> "+vars.get($id.text));} 
         |    st=stringLiteral {System.out.println("> "+$st.value);}
         ) 
         ')' 
    ;

assignment
    :    id=Identifier (Space)* '=' (Space)* st=stringLiteral {vars.put($id.text, $st.value);}
    ;

stringLiteral returns [String value]
    :    '"'
        {StringBuilder b = new StringBuilder();} 
        (    id=Identifier           {b.append($id.text);}
        |    es=EscapeSequence       {b.append($es.text);}
        |    ch=(NormalChar | Space) {b.append($ch.text);}
        |    in=Interpolation        {b.append(vars.get($in.text.substring(2, $in.text.length()-1)));}
        )* 
        '"'
        {$value = b.toString();}
    ;

Interpolation
    :    '${' i=Identifier '}'
    ;

Identifier
    :    ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')*
    ;

EscapeSequence
    :    '\\' SpecialChar
    ;

SpecialChar
    :     '"' | '\\' | '$'
    ;

Space
    :    (' ' | '\t' | '\r' | '\n')
    ;

NormalChar
    :    ~SpecialChar
    ;

Et une classe avec une méthode principale pour tester tout:

package antlrdemo;

import org.antlr.runtime.*;

public class ANTLRDemo {
    public static void main(String[] args) throws RecognitionException {
        String source = "name = \"Bob\";        \n"+
                "msg = \"Hello ${name}\";       \n"+
                "print(msg);                    \n"+
                "print(\"Bye \\${for} now!\");    ";
        ANTLRStringStream in = new ANTLRStringStream(source);
        StrLexer lexer = new StrLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        StrParser parser = new StrParser(tokens);
        parser.parse();
    }
}

qui produit la sortie suivante:

> Hello Bob
> Bye \${for} now!

Encore une fois, je ne suis pas expert, mais (au moins) vous donne a façon de le résoudre.

HTH.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top