我在rascal中有一个简单的文件来指定玩具语法
module temp
import IO;
import ParseTree;
layout LAYOUT = [\t-\n\r\ ]*;
start syntax Simple
= A B ;
syntax A = "Hello"+ ("joe" "pok")* ;
syntax A= "Hi";
syntax B = "world"*|"wembly";
syntax B = C | C C* ;
public void main () {
println("hello");
iprint(parse(#start[Simple], "Hello Hello world world world"));
}
这很好,但问题是我不想写
syntax B = C | C C* ;
我想写
syntax B = ( C | C C* )?
但它被rascal作为解析错误拒绝了 - 尽管所有的
syntax B = ( C C C* )? ;
syntax B = ( C | C* )? ;
syntax B = C | C C* ;
被接受罚款。谁能向我解释我做错了什么?
答案 0 :(得分:2)
序列符号(嵌套序列)在rascal中始终需要括号。元符号定义为
syntax Sym = sequence: "(" Sym+ ")" | opt: Sym "?" | alternative: "(" Sym "|" {Sym "|"}+ ")" | ... ;
所以,在你的例子中你应该写:
syntax B = (C | (C C*))?;
可能令人困惑的是,Rascal使用了|签了两次。一旦分离顶级替代品,一次用于嵌套替代品:
syntax X = "a" | "b"; // top-level
syntax Y = ("c" | "d"); // nested, will internally generate a new rule:
syntax ("c" | "d") = "c" | "d";
最后,正常替代方案的序列没有括号,如:
syntax B
= C
| C C*
;
// or less abstractly:
syntax Exp = left Exp "*" Exp
> left Exp "+" Exp
;
顺便说一句,我们通常避免使用太多嵌套的正则表达式,因为它们是如此匿名,因此使得解析解析树更加困难。正则表达式的最佳用法是表达词法语法,无论如何我们对内部结构不太感兴趣。