Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parsing 创建一个单独的;布尔表达式;动态语言的规则_Parsing_Compiler Construction_Grammar_Bison_Formal Languages - Fatal编程技术网

Parsing 创建一个单独的;布尔表达式;动态语言的规则

Parsing 创建一个单独的;布尔表达式;动态语言的规则,parsing,compiler-construction,grammar,bison,formal-languages,Parsing,Compiler Construction,Grammar,Bison,Formal Languages,我正在Bison中为一种简单的动态类型语言创建语法。我有一个“通用的”表达式规则,它有点类似于C中右值的概念;表达式出现在赋值的右侧,也可以作为参数等发送到函数。该规则的简化版本如下: constantExpression : TOK_INTEGER_CONSTANT | TOK_FLOAT_CONSTANT | stringLiteral ; expression : constantExpression | identifier |

我正在Bison中为一种简单的动态类型语言创建语法。我有一个“通用的”
表达式
规则,它有点类似于C中右值的概念;表达式出现在赋值的右侧,也可以作为参数等发送到函数。该规则的简化版本如下:

constantExpression
    : TOK_INTEGER_CONSTANT
    | TOK_FLOAT_CONSTANT
    | stringLiteral
    ;

expression
    : constantExpression
    | identifier
    | booleanExpression
    | booleanExpression TOK_QUESTION_MARK expression TOK_COLON expression
    | TOK_LPAREN expression TOK_RPAREN
    | expression TOK_PLUS expression
    | expression TOK_MINUS expression
    ;
我还有一个专用的布尔表达式规则;布尔表达式在
if
语句中最常用,但任何其他需要二进制真值的上下文也可以:

booleanExpression
    : identifier
    | expression '<' expression
    | expression '<=' expression
    | expression '==' expression
    | expression '!=' expression
    | expression '>' expression
    | expression '>=' expression
    | booleanExpression '&&' booleanExpression
    | booleanExpression '||' booleanExpression
    | '!' booleanExpression
    | 'true'
    | 'false'
    ;
我知道与运算符优先级相关的shift-reduce冲突,这在这里不是问题,我已经使用运算符的
%left
规则修复了它

program : stmt_list
stmt_list:%empty
        | stmt_list stmt
stmt    : assign
        | call
        | empty
        | while
        | '{' stmt_list '}'
assign  : IDENTIFIER '=' expr ';'
call    : expr '(' expr_list ')' ';'
        | expr '(' ')' ';'
empty   : ';'
while   : "while" '(' boolean_expr ')' stmt
expr_list
        : expr
        | expr_list ',' expr
boolean_expr
        : boolean_term
        | boolean_expr "or" boolean_expr
        | expr '<' expr
boolean_term
        : "true" | "false"
        | expr               { /* insert conversion from expr to boolean */ }

expr    : term
        | expr '+' expr
term    : INTEGER
        | IDENTIFIER
        | '(' expr ')'
我的问题:这个问题的最佳解决方案是什么?我的想法是

  • 以这样一种方式构建规则:尽管存在冲突,野牛 做我想做的事,无视这些警告——非常丑陋和可怕 无法维持
  • 删除单独的
    布尔表达式
    规则并移动 这一切都取决于
    表达式
    -可以,但需要在 语义分析阶段;在我的语言中,字符串不是隐式的 可转换为布尔值,因此像
    if(“foo”)
    这样的代码是不合法的,但是 将被解析器接受
  • 使用GLR解析器-感觉有点 对于这样一个简单的用例来说,使用过度了,但也许我错了

  • 上面哪一个是最好的主意?还有其他我没有考虑过的可能性吗?

    传统智慧是:不要试图在语法中进行语义分析

    首先,它使语法复杂化,即使这是可能的,正如您所看到的。相比之下,在AST上的树遍历中执行类型检查规则时非常简单

    第二,这是不可能的。因为您的语言是动态的,所以您不知道任何变量的类型。因此编译时检查可能会导致三种情况,而不是两种:好、坏和未知。这在语法上会更加复杂,但在语义分析上只会稍微复杂一些

    然而,根据语言的确切性质,可能会选择一个中间立场。通常,一些运算符(布尔运算符和比较运算符)肯定返回布尔值,而某些上下文肯定需要布尔值。因此,您可以添加一个
    boolean\u表达式
    non-terminal,用于指示哪里的结果肯定是布尔值,哪里的值必须是布尔值。然后你可以在语法中插入一个单一的生产单元

     boolean_expression: expression
    
    使用语义操作将运行时检查节点插入AST

    在语义分析过程中,如果确定该检查将始终成功,则可以消除该检查;如果确定该检查将始终失败,则会产生错误。否则,最终将发出代码来执行检查

    此解决方案的优点是,语法随后显示了需要布尔值的上下文,而不需要进行完全强制要求所需的拜占庭式修改

    (在下面的示例中,我只展示了一个布尔运算符、一个比较运算符和一个算术运算符。很明显,一种真正的语言会有更多的布尔运算符、一个比较运算符和一个算术运算符,但它根本不会改变表示形式。我也不关心序言,序言中必须包含运算符的优先级声明。)

    如果你认为上面的内容太复杂,那么就按照传统的观点去做,避免在语法中穿插语义。另一方面,如果你觉得它有解释性的价值,并且你的语言可以接受这些限制,那么就根据你的目的调整它


    笔记:
  • 该方案不依赖于任何“truthy”强制的存在,但如果布尔值是第一类的,则将存在只能在运行时确定为布尔值的表达式(布尔变量、返回布尔值的函数等)。考虑运行时检查,布尔上下文中使用的值是布尔值为强制形式的真实性,其中只有<代码>真< /COD>是真实的,并且只有<代码> false <代码>为false,而所有其他值都会引发错误。

    就我个人而言,我越来越喜欢有限的自动布尔强制。例如,对于我来说,如果文件对象处于错误状态,那么它是虚假的,或者如果容器是非空的,那么它是真实的,这是非常合理的。将这些转换限制为显式布尔上下文,例如条件语句中的条件,使我可以接受自动强制。但我不坚持这个想法;如果你不喜欢它,忽略它

  • 这不是一个很好的名字,但是
    truthy\u或\u falsy\u expr
    似乎太长了,
    boolish\u expr
    似乎太奇怪了。欢迎提出建议


  • 如果它是动态类型的,那么像
    If(“notABool”)
    这样的东西不应该是运行时错误吗?那么
    someVar=“notABool”呢;如果(someVar)
    ,您当前的语法已经允许使用哪一个?您是如何处理的?@sepp2k是的,您给出的第二个示例确实是一个运行时错误
    if(“string”)
    可能已经在解析阶段被拒绝,或者我们可以说string文本创建了一个不能在布尔上下文中使用的对象,并在运行时抛出一个错误。我真的不知道哪种方法更好,这也是我问这个问题的部分原因。通常动态类型语言不会静态地产生任何类型错误,即使在很容易检测到的情况下也是如此。但是,它们可能会产生警告(但是,大多数情况下,这些警告是由外部工具处理的,而不是语言实现本身)。无论是执行静态类型检查(无论是完整的还是不完整的,错误还是警告),这都是语义分析阶段的工作,而不是PAR。
    program : stmt_list
    stmt_list:%empty
            | stmt_list stmt
    stmt    : assign
            | call
            | empty
            | while
            | '{' stmt_list '}'
    assign  : IDENTIFIER '=' expr ';'
    call    : expr '(' expr_list ')' ';'
            | expr '(' ')' ';'
    empty   : ';'
    while   : "while" '(' boolean_expr ')' stmt
    expr_list
            : expr
            | expr_list ',' expr
    boolean_expr
            : boolean_term
            | boolean_expr "or" boolean_expr
            | expr '<' expr
    boolean_term
            : "true" | "false"
            | expr               { /* insert conversion from expr to boolean */ }
    
    expr    : term
            | expr '+' expr
    term    : INTEGER
            | IDENTIFIER
            | '(' expr ')'
    
    program : stmt_list
    stmt_list:%empty
            | stmt_list stmt
    stmt    : assign
            | call
            | empty
            | while
            | '{' stmt_list '}'
    assign  : IDENTIFIER '=' either_expr ';'
    call    : expr '(' expr_list ')' ';'
            | expr '(' ')' ';'
    empty   : ';'
    while   : "while" '(' truthy_expr ')' stmt
    expr_list
            : either_expr
            | expr_list ',' either_expr
    
    truthy_expr
            : boolean_expr
            | expr               { /* insert conversion from expr to boolean */ }
    
    either_expr
            : boolean_expr
            | expr
    
    boolean_expr
            : boolean_term
            | truthy_expr "or" truthy_expr
            | expr '<' expr
    boolean_term
            : "true"
            | "false"
            | '(' boolean_expr ')'
    
    expr    : term
            | expr '+' expr
    term    : INTEGER
            | IDENTIFIER
            | '(' expr ')'