ANTLR:是否可以编写包含自己的词法分析器的嵌套语法?
例如,我的语言中可以使用嵌入式SQL语言:
var Query = [select * from table];
with Query do something ....;
使用ANTLR可以实现这个吗?
能否在嵌入语法中使用自己的词法分析器来构建语法?
如果你是想要在单个语法中定义两种不同的语言(使用独立的词法分析器),那么答案是否定的,这是不可能的。
但是,如果问题是关于是否可以将两种语言解析为单个AST,则答案是:是的,这是可能的。
您只需要:
{
... }
将其插入到主AST中(参见主语法(MyLanguage.g
)中的 expr
规则)。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();};
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();};
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:
如果要允许在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 维基以获取示例语法。
是的,使用AntLR它被称为“岛屿语法”。 您可以在v3示例中获取工作示例,在island-grammar文件夹中:它展示了使用语法解析java代码内的javadoc注释的用法。
您还可以在文档“岛屿语法在解析器控制下”和另一个解决方案中找到一些线索。