ANTLR Можно ли сделать грамматику с помощью встроенной грамматики внутри? - PullRequest
5 голосов
/ 13 октября 2011

ANTLR: возможно ли создать грамматику с помощью встроенной грамматики (со своим собственным лексером) внутри?

Например, в моем языке я могу использовать язык встраивания SQL:

var Query = [select * from table];
with Query do something ....;

Это возможно с ANTLR?

Ответы [ 2 ]

9 голосов
/ 13 октября 2011

Можно ли создать грамматику с встроенной грамматикой (со своим собственным лексером) внутри?

Если вы имеете в виду, возможно ли определить два языка в одной грамматике (используя отдельные лексеры), тогда ответ: нет, это невозможно.

Однако, если вопрос заключается в том, возможно ли анализировать два языка в одном AST, тогда ответ: да, это возможно.

Вам просто нужно:

  • определить оба языка в их собственной грамматике;
  • создать правило лексера в основной грамматике, которое фиксирует весь ввод встроенного языка;
  • использует правило перезаписи, которое вызывает пользовательский метод, который анализирует внешний AST и вставляет его в основной AST, используя { ... } (см. Правило expr в основной грамматике (MyLanguage.g) ).

MyLanguage.g

grammar MyLanguage;

options {
  output=AST;
  ASTLabelType=CommonTree;
}

tokens {
  ROOT;
}

@members {
  private CommonTree parseSQL(String sqlSrc) {
    try {
      MiniSQLLexer lexer = new MiniSQLLexer(new ANTLRStringStream(sqlSrc));
      MiniSQLParser parser = new MiniSQLParser(new CommonTokenStream(lexer));
      return (CommonTree)parser.parse().getTree();
    } catch(Exception e) {
      return new CommonTree(new CommonToken(-1, e.getMessage()));
    }
  }
}

parse
  :  assignment+ EOF -> ^(ROOT assignment+)
  ;

assignment
  :  Var Id '=' expr ';' -> ^('=' Id expr)
  ;

expr
  :  Num
  |  SQL -> {parseSQL($SQL.text)}
  ;

Var   : 'var';
Id    : ('a'..'z' | 'A'..'Z')+;
Num   : '0'..'9'+;
SQL   : '[' ~']'* ']';
Space : ' ' {skip();};

MiniSQL.g

grammar MiniSQL;

options {
  output=AST;
  ASTLabelType=CommonTree;
}

parse
  :  '[' statement ']' EOF -> statement
  ;

statement
  :  select
  ;

select
  :  Select '*' From ID -> ^(Select '*' From ID)
  ;

Select : 'select';
From   : 'from';
ID     : ('a'..'z' | 'A'..'Z')+;
Space  : ' ' {skip();};

Main.java

import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;

public class Main {
  public static void main(String[] args) throws Exception {
    String src = "var Query = [select * from table]; var x = 42;";
    MyLanguageLexer lexer = new MyLanguageLexer(new ANTLRStringStream(src));
    MyLanguageParser parser = new MyLanguageParser(new CommonTokenStream(lexer));
    CommonTree tree = (CommonTree)parser.parse().getTree();
    DOTTreeGenerator gen = new DOTTreeGenerator();
    StringTemplate st = gen.toDOT(tree);
    System.out.println(st);
  }
}

Запустить демо

java -cp antlr-3.3.jar org.antlr.Tool MiniSQL.g 
java -cp antlr-3.3.jar org.antlr.Tool MyLanguage.g 
javac -cp antlr-3.3.jar *.java
java -cp .:antlr-3.3.jar Main

С учетом ввода:

var Query = [select * from table]; var x = 42;

Выход класса Main соответствует следующему AST:

enter image description here

И если вы хотите разрешить строковые литералы внутри вашего SQL (которые могут содержать ]), и комментарии (которые могут содержать ' и ]), вы можете использовать следующее правило SQL внутри вашего SQL. основная грамматика:

SQL
  :  '[' ( ~(']' | '\'' | '-')
         | '-' ~'-' 
         | COMMENT 
         | STR
         )* 
     ']'
  ;

fragment STR 
  :  '\'' (~('\'' | '\r' | '\n') | '\'\'')+ '\'' 
  |  '\'\''
  ;

fragment COMMENT
  :  '--' ~('\r' | '\n')*
  ;

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

[
  select a,b,c 
  from table 
  where a='A''B]C' 
  and b='' -- some ] comment ] here'
]

Просто знайте, что попытка создать грамматику для всего диалекта SQL (или даже большого подмножества) не является тривиальной задачей! Возможно, вы захотите поискать существующие парсеры SQL или посмотрите на вики ANTLR пример грамматики.

2 голосов
/ 13 октября 2011

Да, в AntLR это называется Островная грамматика .Вы можете получить рабочий пример в v3 examples внутри папки островной грамматики: она показывает использование грамматики для разбора комментариев javadoc внутри java-кода.некоторые подсказки в документе Островные грамматики под контролем парсера и это Еще один .

...