Использование StringTemplate в Antlr - PullRequest
1 голос
/ 22 мая 2011

У меня была бы такая проблема: учитывая эти правила

   defField: type VAR ( ',' VAR)* SEP ;  

   VAR : ('a'..'z'|'A'..'Z')+ ;

   type: 'Number'|'String' ;

   SEP : '\n'|';' ;

, где мне нужно связать шаблон с правилом "defField", которое возвращает строку, представляющую xml-схему дляполе, то есть:

   Number a,b,c ;-> "<xs:element name="a" type = "xs:Number"\>" ,also for b and c.

моя проблема в * Клини, то есть, как мне написать шаблон, чтобы сделать то, что я описал выше в свете '*' ??

Спасибо тебе !!!

1 Ответ

6 голосов
/ 23 мая 2011

Соберите все VAR токены в java.util.List с помощью оператора +=:

defField
  :  t=type v+=VAR (',' v+=VAR)* SEP 
  ;  

Теперь v (Список) содержит все VAR.

Затем передайте t и v в качестве параметра методу в вашей StringTemplateGroup:

defField
  :  t=type v+=VAR (',' v+=VAR)* SEP -> defFieldSchema(type={$t.text}, vars={$v})
  ;  

где defFieldSchema(...) должно быть объявлено в вашей StringTemplateGroup, которое может выглядеть следующим образом (файл: T.stg ):

group T;

defFieldSchema(type, vars) ::= <<
<vars:{ v | \<xs:element name="<v.text>" type="xs:<type>"\>
}>
>>

Синтаксис для перебора коллекции выглядит следующим образом:

<COLLECTION:{ EACH_ITEM_IN_COLLECTION | TEXT_TO_EMIT }>

Ответ, поскольку vars является List, содержащим CommonTokens, я взял его атрибут .text вместо того, чтобы полагаться на его метод toString().

Демо

Возьмите следующую грамматику (файл T.g ):

grammar T;

options {
  output=template;
}

defField
  :  t=type v+=VAR (',' v+=VAR)* SEP -> defFieldSchema(type={$t.text}, vars={$v})
  ;  

type
  :  NUMBER
  |  STRING
  ;

NUMBER
  :  'Number'
  ;

STRING
  :  'String' 
  ;

VAR 
  :  ('a'..'z'|'A'..'Z')+ 
  ;

SEP 
  :  '\n'
  |  ';' 
  ;

SPACE
  :  ' ' {skip();}
  ;

, который можно протестировать с помощью следующего класса (файл: Main.java ):

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

public class Main {
  public static void main(String[] args) throws Exception {
    StringTemplateGroup group = new StringTemplateGroup(new FileReader("T.stg"));
    ANTLRStringStream in = new ANTLRStringStream("Number a,b,c;");
    TLexer lexer = new TLexer(in);
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    TParser parser = new TParser(tokens);
    parser.setTemplateLib(group);
    TParser.defField_return returnValue = parser.defField();
    StringTemplate st = (StringTemplate)returnValue.getTemplate();
    System.out.println(st.toString());
  }
}

Как вы увидите, когда вы запустите этот класс, он анализирует входные данные "Number a,b,c;" и выдает следующие выходные данные:

<xs:element name="a" type="xs:Number">
<xs:element name="b" type="xs:Number">
<xs:element name="c" type="xs:Number">

EDIT

Чтобы запустить демонстрацию, убедитесь, что все следующие файлы находятся в одном каталоге:

  • T.g (объединенный файл грамматики)
  • T.stg (файл StringTemplateGroup)
  • antlr-3.3.jar (последняя стабильная сборка ANTLR на момент написания статьи)
  • Main.java (тестовый класс)

затем выполните следующие команды из оболочки / приглашения вашей ОС (из того же каталога, в котором находятся все файлы):

java -cp antlr-3.3.jar org.antlr.Tool T.g  # generate the lexer & parser

javac -cp antlr-3.3.jar *.java             # compile all .java source files

java -cp .:antlr-3.3.jar Main              # run the main class (*nix)
                                           # or
java -cp .;antlr-3.3.jar Main              # run the main class (Windows)         

Вероятно, нет необходимости упоминать, но #, включая текст после него, не должен быть частью команд: это только комментарии, указывающие, для чего эти команды.

...