【问题标题】:ANTLR: using stringTemplateANTLR:使用字符串模板
【发布时间】:2010-05-11 01:58:59
【问题描述】:

(我是 Antlr 的菜鸟)...我在使用 StringTemplates 获得语法时遇到了困难。基本上我正在尝试编写一些 DSL。我可以按照我想要的方式获得我的语法(它可以正确解析),但我无法生成目标代码以使用模板。所以这是我的语法的sn-p:

grammar Pfig;

options { 
    output=template;  
 language=CSharp2;
 }

conf 
    : globalName
    ;


globalName 
    : 'GlobalName:'  ID
     -> localConf(name ={$ID.text})
    ;

我对它进行了相当多的简化,只是为了了解本质。基本上,当 lex/parse 遇到“GlobalName: Foo”时,我希望它根据名为“localConf”的 StringTemplate 吐出文本。超级简单。

现在,让我们在测试应用程序中启动解析器并让它处理输入文件。

// C# processing a file with the lex/parser.
// the 'app.pfig' file just has one line that reads 'GlobalName: Bla'
using (FileStream fs = File.OpenRead("c:\\app.pfig"))
        {
            PfigParser parser = new PfigParser(new CommonTokenStream(
                new PfigLexer(new ANTLRInputStream(fs))));

            using (TextReader tr = File.OpenText("./Pfig.stg"))
            {
                parser.TemplateLib = new StringTemplateGroup(tr);
            }

            var parseResult = parser.conf();
            string code = parseResult.Template.ToString(); // Fail: template is null
        }

我可以单步执行解析器代码并查看它是否正确识别了我的文本并正确应用了 stringTemplate。问题是,由于这个“globalName”规则是“conf”的子规则,它不会直接执行——该方法只是找到它并返回。但是调用 'Conf' 方法并没有保留子规则的返回值——它变得毫无意义。这意味着我在最后一行生成的模板为空。

如果我去掉语法中的“conf”规则并直接调用“globalName”,它将起作用(因为它是堆栈上的唯一规则)。但我显然想要不止一条规则。我用 Java 生成了解析器,它做同样的事情:

// antlr generated parser code
public PfigParser.conf_return conf() // throws RecognitionException [1]
{   
    PfigParser.conf_return retval = new PfigParser.conf_return();

    try 
 {
        {
         PushFollow(FOLLOW_globalName_in_conf30);
         globalName(); // <- it calls globalName() but doesn't keep the return.
         state.followingStackPointer--;

        }

        retval.Stop = input.LT(-1);

    }

// snip

很容易看出我没有了解模板方法应该如何与 Antlr 一起使用的一些基本概念。 我很确定这是我的问题,但我不知道自己做错了什么...我看到的示例并没有真正显示真实世界的模板发射代码。

【问题讨论】:

    标签: antlr antlr3


    【解决方案1】:

    基本上,您需要将模板输出显式转发到子规则:

    conf 
        : a=globalName -> {$a.st}
        ;
    

    它并不漂亮,但很有效。

    【讨论】:

      【解决方案2】:

      看来我终于抓住了模板的想法 :) 模板应该分层地“嵌套”到另一个中。下面的例子工作得很好:

      模板测试.g:

      grammar TemplatesTest;
      
      options
      {
          output=template;
          language=CSharp2;
      }
      
      ID  :   ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
          ;
      
      INT :   '0'..'9'+
          ;
      
      COMMENT
          :   '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
          |   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
          ;
      
      WS  :   ( ' '
              | '\t'
              | '\r'
              | '\n'
              ) {$channel=HIDDEN;}
          ;
      
      STRING
          :  '\'' ( ESC_SEQ | ~('\\'|'\'') )* '\''
          ;
      
      fragment
      HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;
      
      fragment
      ESC_SEQ
          :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
          |   UNICODE_ESC
          |   OCTAL_ESC
          ;
      
      fragment
      OCTAL_ESC
          :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
          |   '\\' ('0'..'7') ('0'..'7')
          |   '\\' ('0'..'7')
          ;
      
      fragment
      UNICODE_ESC
          :   '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
          ;
      
      doc
          : (e+=expr)+ -> doc(expressions={$e})
          ;
      
      expr
          : ID '=' INT -> expression(id={$ID.text}, value={$INT.text})
          ;
      

      模板测试.stg:

      group TemplatesTest;
      
      doc(expressions) ::=
      <<
      srart expressions
      <expressions; separator="\n">
      end
      >>
      
      expression(id, value) ::= 
      <<
      <id> := <value>;
      >>
      

      测试 C# 代码:

      var lexer = new TemplatesTestLexer(new ANTLRFileStream("sample.txt"));
      var parser = new TemplatesTestParser(new CommonTokenStream(lexer));
      
      using (var reader = new StreamReader("TemplatesTest.stg"))
      {
        parser.TemplateLib = new StringTemplateGroup(reader);
      }
      
      var doc = parser.doc();
      Console.WriteLine(doc.Template);
      

      示例输入:

      a = 5
      b = 6
      c = 7
      

      输出是:

      srart expressions
      a := 5;
      b := 6;
      c := 7;
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多