JavaCC 中的标记:确保符号在一行中是单个的

Token in JavaCC: make sure that a symbol is single on a line

我需要"{" 将单行。因此,我必须使用识别它的令牌。这是正确的例子:

1
2
program
{

1
2
3
4
5
program



{

这是不正确的例子:

1
program {

1
2
program
{ sentence;

然后我有一个这样的令牌:

1
2
3
4
5
TOKEN: { < openKey:"{">   {System.out.print(image +"\
");}}
SKIP: { < ("" |"\
" |"\\t" |"\
" )+ > }

但我想不出如何使符号 "{" 恰好在一个或多个 "\\\\
"。在识别它之后,我必须准确地写:

1
2
program
{

如果我尝试:

1
2
3
4
5
6
TOKEN: { < openKey: ("" |"\
" |"\\t" |"\
" )+"{" ("" |"\
" |"\\t" |"\
" )+ >   {System.out.print(image +"\
");}}

这运行,但它写了这么多 "\\\\
" 就像在输入中一样。


我做的不一样:

1
2
3
4
5
6
7
8
9
TOKEN: { < openKey:"\
" ("" |"\\t")*"{" ("" |"\\t")* ("\
" |"\
") >{System.out.print("{\
\
");}}  
SKIP: {"" |"\
" |"\\t" |"\
" }

回车有一些问题,但是这种方式效果很好。


基本问题是您在没有任何解释的情况下打印输入。换句话说,正如您所发现的那样,进去的就是出来的。

为了使其更易于阅读 --- 并且为了避免在某些方面通过强制它完成整个任务来滥用词法分析器 --- 我建议将您的 print 语句向下移动到解析器中(例如,在Start() 函数)。 (实际上,我倾向于将所有输出完全移出解析器,除非我正在做一些我永远不会重用的非常小的事情,但这是另一个问题。)

接下来,为了解决实际问题,您需要做一些解释,从一堆换行符变成一个换行符。最简单的方法是基本的 replaceAll。这是我的 Start() 函数,其中 openKey 的定义与您所做的一样,WORD 只是字母的串联。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void Start() :
{
  Token t;
}
{
    (
      t = <WORD>
      {System.out.print((t.image).replaceAll("(\
)+","\
"));}
    )*
    (
            t = <openKey>
            {System.out.print((t.image).replaceAll("(\
)+","\
"));}
            (
              t = <WORD>
              {System.out.print((t.image).replaceAll("(\
)+","\
"));}
            )*
    )*
    <EOF>

}

所以基本上,这需要零个或多个单词,后跟一个由 1 个或多个换行符组成的单元,后跟左花括号,后跟 1 个或多个换行符,然后是零个或多个单词,并输出单词,花括号,每个 1 个或多个换行符集只有 1 个换行符。

如果你可以用大括号开始一个文件,而不是需要一个单词,那么它会输出空行、大括号和换行符。我不知道这是否是你想要的,能够以空行开始输出,所以你需要使用输出代码来获得你想要的确切格式,另外,你可以看到你那里有一些非常好的重复代码,可以提取到一个函数中,所以我把它留给读者练习。

无论如何,这个答案的基本前提是——而且我相信这确实是一个古老的格言,适用于生活的所有领域,而不仅仅是编码——"除非你改变你所采取的在输出之前,它会和你输入的完全一样!"