-1

我想试试这个工具,antlr,这样我最终可以解析一些代码并重构它。我尝试了一些小语法,一切正常,所以我采取了下一步,开始解析一种简单的 C#。
好消息:了解基础知识大约需要 10 分钟。
极端的坏消息:理解如何解析两个空格而不是一个空格需要几个小时。真的。这东西讨厌空格,告诉你这一点并不羞耻。老实说,我开始认为它无法解析它们,但后来事情进展顺利......或者至少我是这么认为的。

现在,空间问题出现在 ANTLRWorks 尝试分配半 GB 内存并且无法真正解析任何内容之后。

语法不是很难,我是初学者:

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)* ;

但是仍然在添加globFileglobNamespace添加时,ide 开始分配内存,就像没有明天一样,这显然是一个问题。

所以

- 这种捕捉空格的方式对吗?(我不想跳过它们,这就是重点)
- 内存泄漏是因为我看不到的递归吗?

这个东西能够解析的代码是这样的:

import System;

namespace aNamespace{
    class aClass{
    }
}

globFile顺便说一句,这是主要规则。

4

2 回答 2

2

您应该定义一个词法分析器标记以按照您需要的方式处理空格。如果您希望一组连续的空格或制表符组成一个标记,请使用如下定义。在这种情况下,您将在解析器规则中引用空白作为Whitespace(必需)或Whitespace?(可选)。

// ANTLR 3:
Whitespace : (' ' | '\t')+;

// ANTLR 4:
Whitespace : [ \t]+;

如果您希望每个单独的空白字符都成为自己的标记,请使用以下内容。在这种情况下,您将在解析器规则中引用空白作为Whitespace+(必需)或Whitespace*(可选)。

// ANTLR 3:
Whitespace : ' ' | '\t';

// ANTLR 4:
Whitespace : [ \t];

关于内存泄漏的问题可能属于 ANTLRWorks 问题跟踪器。

于 2013-05-02T16:24:09.653 回答
1

问题实际上是最后一条规则

globFile : (globImport | spaceLNsOpt)* (globNamespace | spaceLNsOpt)* ;

我是这样改的:

globFile : (globImport spaceLNsOpt)* (globNamespace spaceLNsOpt)* ;

似乎添加 EOF显然有帮助:

globFile : (globImport spaceLNsOpt)* (globNamespace spaceLNsOpt)* EOF ;

但这还不够,规则在任何情况下都无法发挥作用。

于 2013-05-03T13:13:13.157 回答