Parsing 如何在语法中使用空格?

Parsing 如何在语法中使用空格?,parsing,grammar,bison,context-free-grammar,Parsing,Grammar,Bison,Context Free Grammar,我想为简化版的LISP创建解析器/词法分析器。以下是bison/lexer规格: /* Lexer file */ "(" {return OP;} ")" {return CP;} [0-9]+ {return NUM;} ["][a-zA-Z]*["] { return STR; } [ \n\r\f] { /*do nothing*/} . {return INVALID_TOKEN;} /* Bison file */ start_expr: components_list

我想为简化版的LISP创建解析器/词法分析器。以下是bison/lexer规格:

/* Lexer file */
"(" {return OP;}
")" {return CP;}
[0-9]+ {return NUM;}
["][a-zA-Z]*["] { return STR; }
[ \n\r\f]     { /*do nothing*/}
. {return INVALID_TOKEN;}

/* Bison file */
start_expr: components_list

components_list : /*nothing*/
     | components_list component

 component : OP STR NUM CP
这样的字符串符合语法
(“f”1)(“f”1)(“f”1)(“f”1)
。但是表达式
(“f”1)
对我来说非常糟糕,我决定在语法中添加明确的分隔符(使用
空格
标记
[\n\r\f]+
)。诸如此类:

opt_wspace : /*nothing*/
   | WHITESPACE

start_expr: components_list

components_list : /*nothing*/
     | components_list component

 component : OP opt_wspace STR WHITESPACE NUM opt_wspace CP
但是现在(对我来说)语法看起来很糟糕,但是类似
(“f”1)
的表达式是不允许的。另一个时刻是,现在我很容易犯语法错误。例如,这样的表达式将不会被解析
(“f”1)(“f”1)
(我忘了在
组件列表中添加
opt\u wspace
的用法)

所以我的基本问题是如何在语法中使用分隔符/空格?我查看了python()的语法,但它似乎没有提到空格表达式/标记。下面是一段小引语:

stmt:简单的|复合的|stmt

简单语法:小语法(“;”小语法)*[“;”]换行

小型:(expr|stmt | del|stmt | pass|stmt | flow|stmt)| 导入|全局|非本地|断言|

expr|stmt:testlist_star|expr(annassign|augsign(yield|expr|testlist)| [('='(yield|expr | testlist_star_expr))+[TYPE_COMMENT]]

我所知道的所有Lisp(或者真正的编程语言)都不会强迫您在标记之间放置空格。例如,
(显示“hello”)
(格式t“~d”42)
分别在Scheme和Common Lisp中工作良好。所以你尝试去做的事情并不常见,我建议你不要去做

这就是说,如果您确实希望在某些令牌之间强制使用空格,那么您的两个选项是要么继续执行您正在执行的操作,要么为无效令牌定义一个规则,该规则与您想要禁止的任何令牌序列相匹配。大概是这样的:

[0-9]+ {return NUM;}
["][^"]*["] { return STR; }
(["][^"]*["]|[0-9]+){2,} { return INVALID_TOKEN; }
因此,每当多个字符串或数字相邻出现且中间没有任何内容时,就会生成
无效的\u标记。当您添加更多类型的令牌时,这种模式将变得越来越复杂,您不希望这些令牌彼此相邻(例如标识符)


PS:只允许字符串中的字母是非常不寻常的,这就是为什么我在上面更改了字符串文本的正则表达式。您可能需要进一步调整它,以允许在字符串中使用转义双引号。

我不同意您的看法。例如,在
racket
中,你不能写这样的东西
(structаa([x:Real])
,只有
(structаa([x:Real]))
@LmTinyToon,这是因为
x:Real
是一个有效的标识符。是的,我同意你的看法。