我想为动态类型语言创建一个解析器 .
在我的野牛文件中,我有 runtimetyped
的规则,这是一个变量名或函数调用 .
runtimetyped : T_ID { $$ = create_identifier($1); }
| call { $$ = $1; }
;
我还想在编译时进行一些基本的类型检查 . F.E.我不想允许这样的事情
x = "string" + 42 <= true;
在源代码中,我想创建一个编译时错误 .
但是像
s = "string";
i = 42;
b = true;
x = s + i <= b;
应该产生运行时错误 .
我的方法是在语法中有不同的表达方式:
expression : bool_expression
| math_expression
| string_expression
;
这些 expressions
中的任何一个都由 terms
, factors
等构建 .
a factor
也可能始终是 runtimetyped
,这会导致 reduce/reduce
错误 .
math_factor : numeric_literal { $$ = $1; }
| runtimetyped { $$ = $1; }
| T_LPAREN math_expression T_RPAREN { $$ = $2; }
;
bool_factor : T_BOOL { $$ = create_bool($1); }
| runtimetyped { $$ = $1; }
| compare { $$ = $1; }
| T_LPAREN bool_expression T_RPAREN { $$ = $2; }
;
string_expression : T_STRING { $$ = $1; }
| runtimetyped { $$ = $1; }
| string_expression T_STROP string_expression { $$ = create_expression($2, $1, $3); }
;
我用 bison -v parser.y
运行它 .
任何人都可以给我一个关于如何解决冲突和/或究竟是什么导致冲突的暗示 .
提前致谢 .
1 回答
在编译期间键入检查的最佳方法是对AST进行分析 . 为了提供准确的错误消息,您需要保留AST中每个令牌的位置信息,但这通常很有用 .
在构建AST之后进行语义分析的优点是代码更清晰,因为它不会将语义分析与其他任务混合 . 它还允许您使用更多信息,例如类型声明 . 但是,如果您不想这样做,您还可以在每个 生产环境 的操作中进行类型检查 . 这将语义分析扩展到整个语法,恕我直言更难理解,验证,测试和维护 . 不过,这是有可能的 .
将语义检查转换为语法错误实际上是最糟糕的做事方式 . 它不必要地使语法复杂化,并且使得生成良好的错误消息变得更加困难,因为类型错误实际上不是语法错误,并且大多数尝试用您的语言编写代码的人会因为语法错误而在语法上接受语法错误而感到困惑无意义的构造 .
尽管如此,这是可能的 . 但是,您需要非常小心地避免语法模糊,这通常会表现为减少/减少冲突,这正是您所看到的 . (你没有提供足够的语法来诊断准确的问题,但是你可以自己通过将
-v
标志的语法处理到bison
然后检查生成的.output
文件,它将显示有关的状态 . 冲突 . )冲突的最可能原因是单元制作的解决,在可能有
x_expression
和y_expression
的情况下(不看前瞻标记) . 在这里,您可能需要执行其中一个产品x_expression: x_factor
或y_expression: y_factor
,这反过来意味着您可能需要x_factor: runtimetyped
或y_factor: runtimetyped
之一,并且可能无法做出该决定 . (这是LALR(1)
状态合并可能会产生"mysterious"冲突的情况之一 . )