我想为LISP的简化版本创建解析器/词法分析器。这是野牛/ 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)
对我来说似乎很糟糕,我决定在语法中添加明显的定界符(WHITESPACE
类标记[ \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_wspace
中添加components_list
的用法)。
所以我的基本问题是如何在语法中使用定界符/空格?我看了python(https://github.com/python/cpython/blob/master/Grammar/Grammar)的语法,但似乎没有提及空格表达式/令牌。这是次要的报价:
stmt:simple_stmt | compound_stmt
simple_stmt:small_stmt(';'small_stmt)* [';'] NEWLINE
small_stmt:(expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt)
expr_stmt:testlist_star_expr(annassign | augassign(yield_expr | testlist)| [('='(yield_expr | testlist_star_expr))+ [TYPE_COMMENT]])
答案 0 :(得分:1)
我不知道的任何修补程序(或通常说来的编程语言)都没有强迫您在这样的令牌之间放置空格。例如,(display"hello")
或(format t"~d"42)
之类的东西分别在Scheme和Common Lisp中可以正常工作。因此,您尝试做的事情通常不会完成,我建议您不要这样做。
也就是说,如果您确实想在某些令牌之间强制使用空格,则两个选择是要么继续做您正在做的事情,要么为无效令牌定义一个规则,该规则与要禁止的任何令牌序列匹配。像这样:
[0-9]+ {return NUM;}
["][^"]*["] { return STR; }
(["][^"]*["]|[0-9]+){2,} { return INVALID_TOKEN; }
因此,只要多个字符串或数字彼此相邻出现而在两者之间没有任何东西,就会生成INVALID_TOKEN
。当您添加不想彼此相邻的更多类型的令牌(例如标识符)时,这种模式将变得越来越复杂。
PS:只允许字符串中的字母是非常不寻常的,这就是为什么我在上面更改了字符串文字的正则表达式的原因。您可能需要进一步调整它,以允许在字符串中使用转义的双引号。