سؤال

أنا أعمل على معالجة سلسلة بسيطة DSL لأغراض داخلية، وأود أن اللغة لدعم الاستيفاء السلسلة كما هو مستخدم في روبي.

علي سبيل المثال:

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

أحاول تنفيذ محلل محللي في Antlrv3، لكنني عديم الخبرة في استخدام Antlr، لذلك أنا غير متأكد من كيفية تطبيق هذه الميزة. حتى الآن، لقد حددت حرفي السلسلة في Lexer، ولكن في هذه الحالة، سأحتاج إلى التعامل مع محتوى الاستيفاء في المحلل المحلل.

بلدي سلسلة القواعد الحرفية الحالية يشبه هذا:

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

إن نقل السلسلة المعالجة الحرفية إلى المحلل يبدو أن كل شيء آخر يتوقف عن العمل كما ينبغي. لا تسفر عن عمليات البحث على شبكة الإنترنت عن أي معلومات. أي اقتراحات حول كيفية البدء في هذا؟

هل كانت مفيدة؟

المحلول

أنا لا خبير من أنلوب، لكن إليك قواعد قواعد محتملة:

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
    ;

كما تلاحظ، هناك بضعة (Space)*-، داخل النحو المثال. هذا بسبب stringLiteral هو الحظائر الحظيرة بدل من Lexer- القاعدة. وبعد لذلك، عند تشغيل الملف المصدر، لا يمكن ل Lexer معرفة ما إذا كانت مساحة بيضاء جزء من سلسلة حرفية، أو هي مجرد مساحة داخل الملف المصدر الذي يمكن تجاهله.

لقد اختبرت المثال مع فئة Java صغيرة وكلها تعمل كما هو متوقع:

/* 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
    ;

وفئة ذات طريقة رئيسية لاختبار كل شيء:

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();
    }
}

الذي ينتج الإخراج التالي:

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

مرة أخرى، أنا لا خبير، ولكن هذا (على الأقل) يمنحك أ طريقة لحلها.

hth.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top