我正在使用ANTLR V3为DSL语言生成C#代码.
生成的代码在laxer和parser类上都包含属性CLSCompliant,这会导致生成警告,因为我的项目不符合CLS.
我正在编写一个程序,我需要解析一个JavaScript源文件,提取一些事实,并插入/替换部分代码.根据以下代码,我需要做的事情的简化描述:
foo(['a', 'b', 'c']);
Run Code Online (Sandbox Code Playgroud)
提取'a','b'和'c',并将代码重写为:
foo('bar', [0, 1, 2]);
Run Code Online (Sandbox Code Playgroud)
我正在使用ANTLR来解析我的需求,生成C#3代码.其他人已经提供了JavaScript语法.解析源代码是有效的.
我遇到的问题是弄清楚如何实际正确分析和修改源文件.我尝试实际解决问题的每种方法都让我陷入了死胡同.我不禁想到我没有按照预期使用该工具,或者在处理AST时只是太过新手.
我的第一种方法是使用a解析TokenRewriteStream并实现EnterRule_*我感兴趣的规则的部分方法.虽然这似乎使得令牌流的修改变得非常简单,但是我的分析没有足够的上下文信息.似乎所有我可以访问的是一个平坦的令牌流,这并没有告诉我足够的整个代码结构.例如,要检测是否foo正在调用该函数,只需查看第一个令牌就行不通,因为它也会错误地匹配:
a.b.foo();
Run Code Online (Sandbox Code Playgroud)
为了让我能够进行更复杂的代码分析,我的第二种方法是使用重写规则修改语法以生成更多的树.现在,第一个示例代码块产生:
Program
CallExpression
Identifier('foo')
ArgumentList
ArrayLiteral
StringLiteral('a')
StringLiteral('b')
StringLiteral('c')
这对于分析代码非常有用.但是,现在我无法轻易地重写代码.当然,我可以修改树结构来表示我想要的代码,但我不能用它来输出源代码.我曾希望与每个节点相关联的令牌至少能给我足够的信息来知道我需要在原始文本中进行修改的位置,但我得到的只是令牌索引或行/列号.要使用行号和列号,我必须在源代码中进行尴尬的第二次传递.
我怀疑我在理解如何正确使用ANTLR做我需要的东西时遗漏了一些东西.有没有更合适的方法来解决这个问题?
在利用ANTLR 3.3时,我正在改变当前语法以支持没有括号的输入.这是我的语法的第一个版本:
grammar PropLogic;
NOT : '!' ;
OR : '+' ;
AND : '.' ;
IMPLIES : '->' ;
SYMBOLS : ('a'..'z') | '~' ;
OP : '(' ;
CP : ')' ;
prog : formula EOF ;
formula : NOT formula
| OP formula( AND formula CP | OR formula CP | IMPLIES formula CP)
| SYMBOLS ;
WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; } ;
Run Code Online (Sandbox Code Playgroud)
然后我改变它以支持适当的功能: …
我使用正常的空白分隔到隐藏的通道,但我有一个规则,我想包括任何空格以便以后处理,但我发现的任何例子都需要一些非常奇怪的手动编码.
没有简单的选项可以从多个渠道中读取,例如从一开始就将空白放在那里的选项.
防爆.这是WhiteSpace词法分析器规则
WS : ( ' '
| '\t'
| '\r'
| '\n'
) {$channel=HIDDEN;}
;
Run Code Online (Sandbox Code Playgroud)
这是我的规则,我想包括空格
raw : '{'? (~('{'))*;
Run Code Online (Sandbox Code Playgroud)
基本上它捕获所有规则来捕获与其他模式不匹配的其他规则的内容,因此我需要原始流.
我希望有一个{$channel==DEFAULT || $channel==HIDDEN}语法示例,但找不到任何.
我的目标是C#,但如果需要,我可以重写Java示例.
我有一个语法,我想在(像f(x,y))中包含多参数函数.我正在使用AST输出和我自己的树解析器.现在我的参数列表生产是
paramdefs: (ID COMMA)* ID ;
Run Code Online (Sandbox Code Playgroud)
这工作正常,但AST输出
z(x,y)=expression
Run Code Online (Sandbox Code Playgroud)
是
(FUNC (z)(x)(,)(y)(expression))
Run Code Online (Sandbox Code Playgroud)
(即它很平坦).
该FUNCCommonTree的孩子,在一般情况下,都是{ function name,parameter,comma,parameter,defined expression},对于任何数量的参数.我希望参数列表是一个单独的子项而不是逗号(这样可以更容易地遍历树).
理想情况下,这就是树的样子:
(FUNC (z)((x)(y))(expression))
Run Code Online (Sandbox Code Playgroud)
(注意没有逗号元件的和的分组x和y.
语法的相关相关领域:
funcdef: ID '(' paramdefs ')' '=' expr -> ^(FUNC ID paramdefs expr) ;
paramdefs: (ID COMMA)* ID ;
Run Code Online (Sandbox Code Playgroud) 我目前正在使用ANTLR创建一个或多或少简单的表达式求值程序.
我的语法很简单(至少我希望如此),看起来像这样:
grammar SXLGrammar;
options {
language = Java;
output = AST;
}
tokens {
OR = 'OR';
AND = 'AND';
NOT = 'NOT';
GT = '>'; //greater then
GE = '>='; //greater then or equal
LT = '<'; //lower then
LE = '<='; //lower then or equal
EQ = '=';
NEQ = '!='; //Not equal
PLUS = '+';
MINUS = '-';
MULTIPLY = '*';
DIVISION = '/';
CALL;
}
@header {
package somepackage;
}
@members {
}
@lexer::header { …Run Code Online (Sandbox Code Playgroud) 我是一名ANTLR初学者,想要计算符号的SHA1-Hash.
我的简化示例语法:
grammar Example;
method @after{calculateSha1($text); }: 'call' ID;
ID: 'A'..'Z'+;
WS: (' '|'\n'|'\r')+ {skip(); }
COMMENT: '/*' (options {greedy=false;}: .)* '*/' {$channel=HIDDEN}
Run Code Online (Sandbox Code Playgroud)
由于词法分析器删除了不同字符串的所有空格callABC,call /* DEF */ ABC不幸的是得到相同的SHA1-Hash值.
是否有可能在开始和结束标记之间获取规则的"原始"文本以及所有跳过的空格和其他通道的文本?
(我想到的一种可能性是成员WS- 和 - COMMENT工具规则中的所有字符,但是还有更多规则,所以这不太实用.)
我使用标准的ANTLRInputStream来提供Lexer,但我不知道如何接收原始文本.
我正在尝试使用ANTLR 3解析Java Server Pages.
Java对单个方法的字节代码有64k的限制,并且在编译ANTLR生成的Java源代码时,我一直遇到"代码太大"的错误.
在某些情况下,我已经能够通过妥协我的词法分析器来修复它.例如,JSP使用XML"Name"标记,该标记可以包含各种各样的字符.我决定只在我的"Name"标记中接受ASCII字符,这大大简化了一些测试,而lexer允许它编译.
但是,我已经到了无法削减任何角落的地步,但DFA仍然太复杂了.
是否存在导致复杂DFA的常见错误?
有没有办法抑制DFA的产生,可能依靠语义谓词或固定的先行来帮助预测?
手写这个词法分析器很容易,但在我放弃ANTLR之前,我想确保我不会忽略一些明显的东西.
ANTLR 3词法分析器使用DFA来决定如何标记输入.在生成的DFA中,有一个名为的方法specialStateTransition().此方法包含一个switch语句,其中包含DFA中每个状态的大小写.在每种情况下,都有一系列if陈述,每个陈述用于从州过渡.每个if语句的条件测试输入字符以查看它是否与转换匹配.
这些字符测试条件可能非常复杂.它们通常具有以下形式:
int ch = … ; /* "ch" is the next character in the input stream. */
switch(s) { /* "s" is the current state. */
…
case 13 :
if ((('a' <= ch) && (ch <= 'z')) || (('A' <= ch) && (ch <= 'Z')) || … )
s = 24; /* If the character …Run Code Online (Sandbox Code Playgroud) 我已经从Antlr 3升级到Antlr 4.我使用此代码来捕获使用此代码的异常.但这不适用于Antlr 4.
partial class XParser
{
public override void ReportError(RecognitionException e)
{
base.ReportError(e);
Console.WriteLine("Error in Parser at line " + ":" + e.OffendingToken.Column + e.OffendingToken.Line + e.Message);
}
}
Run Code Online (Sandbox Code Playgroud)
这是出现的错误
'Parser.ReportError(Antlr4.Runtime.RecognitionException)': no suitable method found to override
Run Code Online (Sandbox Code Playgroud)
在Antlr 4中,累积输入流中发生的错误的预期方式是什么.我无法在网上找到实现这一目标的方法.请给我一些指导.
编辑:
我已经实现了XParser,如下所示
partial class XParser : IAntlrErrorListener<IToken>
{
public void SyntaxError(IRecognizer recognizer, IToken offendingSymbol, int line, int charPositionInLine, string msg, RecognitionException e)
{
Console.WriteLine("Error in parser at line " + ":" + e.OffendingToken.Column + e.OffendingToken.Line + e.Message);
}
} …Run Code Online (Sandbox Code Playgroud) 对于antlr4,有没有好的CSS语法?我知道antlr3有一些语法,但事实证明,如果没有"词法分析器模式"(在v4中添加),CSS解析并不容易.为什么?
考虑以下CSS选择器:
.hello.world { /* ... */ }
.hello .world { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
在大多数语法中,空格只是被忽略了.但是如果忽略空格,就无法在解析器级别区分上面的两个选择器.
再说一遍,如果你不忽略空格,那么语法会变得非常嘈杂吗?或WS*模式无处不在,因为空格几乎没有意义,除非它出现在选择器中.
这是来自antlr4的模式的来源,因为只要你输入不同的上下文(即不要忽略"selector"上下文中的空格),你就可以为词法分析器模式定义词法分析器的新规则.
也就是说,我会接受antlr3的任何语法,只要它正确处理空格,因为这是我们现在正在使用的版本;-)