我想尝试这个工具,antlr,这样我最终可以解析一些代码并重构它。我尝试了一些小语法,一切都很好,所以我采取了下一步,开始解析一种简单的C#。
好消息:了解基础知识需要10分钟
极端坏消息:理解如何解析两个空格而不是一个空格需要几个小时。真。这件事讨厌空白,告诉你这一点并不羞耻。老实说,我开始认为无法来解析它们,但随后出现了正确的方式......或者至少我是这么认为的。
现在空间问题出现在ANTLRWorks试图分配半GB的ram并且无法真正解析任何内容之后。
语法不是很难,我是初学者:
grammar newEmptyCombinedGrammar;
TokenEndCmd : ';' ;
TokenGlobImport : 'import' ;
TokenGlobNamespace : 'namespace' ;
TokenClass : 'class' ;
TokenSepFloat : ',' ;
TokenSepNamespace : '.' ;
fragment TokenEmptyString : '' ;
TokenUnderscore : '_' ;
TokenArgsSep : ',' ;
TokenArgsOpen : '(' ;
TokenArgsClose : ')' ;
TokenBlockOpen : '{' ;
TokenBlockClose : '}' ;
// --------------------
Digit : [0-9] ;
numberInt : Digit+ ;
numberFloat : numberInt TokenSepFloat numberInt ;
WordCI : [a-zA-Z]+ ;
WordUP : [A-Z]+ ;
WordLW : [a-z]+ ;
// -----------------
keyword : (WordCI | TokenUnderscore+) (numberInt | WordCI | TokenUnderscore)* ;
// ---------------------
spaces : (' ' | '\t')+ ;
spaceLNs : (' ' | '\t' | '\r' | '\n')+ ;
spacesOpt : spaces* ;
spaceLNsOpt : spaceLNs* ;
// ---------------------
// tipo "System" o "System.Net.Socket"
namepaceNameComposited : keyword (TokenSepNamespace keyword)* ;
// import System; import System.IO;
globImport : TokenGlobImport spaces namepaceNameComposited spacesOpt TokenEndCmd ;
// class class1 {}
namespaceClass : TokenClass spaces keyword spaceLNsOpt TokenBlockOpen spaceLNsOpt TokenBlockClose ;
// "namespace ns1 {}", "namespace ns1.sns2{}"
globNamespace : TokenGlobNamespace spaces namepaceNameComposited spaceLNsOpt TokenBlockOpen spaceLNsOpt namespaceClass spaceLNsOpt TokenBlockClose ;
globFile : (globImport | spaceLNsOpt)* (globNamespace | spaceLNsOpt)* ;
但是当添加globFile
或globNamespace
时,ide开始分配内存,就像没有明天一样,这显然是一个问题。
- 这种捕捉空白的方式是正确的吗? (我不想跳过它们,这就是重点)
- 我没有看到递归的内存泄漏?
这个东西能够解析的代码如下:
import System;
namespace aNamespace{
class aClass{
}
}
顺便说一下, globFile
是主要规则。
答案 0 :(得分:2)
您应该定义一个词法分析器令牌来按照您需要的方式处理空格。如果希望一组连续的空格或制表符形成单个标记,请使用如下定义。在这种情况下,您可以将解析器规则中的空格引用为Whitespace
(必需)或Whitespace?
(可选)。
// ANTLR 3:
Whitespace : (' ' | '\t')+;
// ANTLR 4:
Whitespace : [ \t]+;
如果您希望每个单独的空白字符都是自己的标记,请使用以下内容。在这种情况下,您可以将解析器规则中的空格引用为Whitespace+
(必需)或Whitespace*
(可选)。
// ANTLR 3:
Whitespace : ' ' | '\t';
// ANTLR 4:
Whitespace : [ \t];
关于内存泄漏的问题可能属于ANTLRWorks问题跟踪器。
答案 1 :(得分:1)
问题实际上是最后一条规则
globFile : (globImport | spaceLNsOpt)* (globNamespace | spaceLNsOpt)* ;
我这样改了:
globFile : (globImport spaceLNsOpt)* (globNamespace spaceLNsOpt)* ;
似乎添加EOF 显然有助于:
globFile : (globImport spaceLNsOpt)* (globNamespace spaceLNsOpt)* EOF ;
但这还不够,规则在任何情况下都无法发挥作用。