0

我正在与野牛一起工作,目前遇到了一个问题,并且对所有这些工作方式非常陌生,我需要能够判断一个特定的产品是否是 > 或 + 或 >= 但我不知道最好的方法存储和检索此值,这是以下代码:

%union 
{
  char* text;
  TYPE_INFO typeInfo;
};

N_ARITHLOGIC_EXPR   : N_UN_OP N_EXPR
            {
                if($2.type == FUNCTION){
                    yyerror("Arg 1 cannot be function");
                }
                $$.type = BOOL;
                $$.numParams = NOT_APPLICABLE;
                $$.returnType = NOT_APPLICABLE;

            }
            | N_BIN_OP N_EXPR N_EXPR
            {
                if(T_LT || T_GT || T_LE || T_GE || T_EQ || T_NE || T_NOT){
                    if(!(($2.type == INT && $3.type == INT) || ($2.type == STR && $3.type == STR))){
                        yyerror("Arg n must be integer or string");
                    }
                    else{
                        $$.type = BOOL;
                        $$.numParams = NOT_APPLICABLE;
                        $$.returnType = NOT_APPLICABLE;
                    }
                }
                else if(T_AND || T_OR){
                    if(($2.type == INT && $3.type == FUNCTION) || ($2.type == STR && $3.type == FUNCTION) || ($2.type == BOOL && $3.type == FUNCTION) || ($2.type == FUNCTION && $3.type == FUNCTION)){
                        yyerror("Arg n cannot be a function");
                    }
                    else{
                        $$.type = BOOL;
                        $$.numParams = NOT_APPLICABLE;
                        $$.returnType = NOT_APPLICABLE;                         
                    }
                }
                else if (T_ADD || T_SUB || T_MULT || T_DIV){
                    if(!($2.type == INT && $3.type == INT)){
                        yyerror("Arg n must be integer");
                    }
                    else{
                        $$.type = INT;
                        $$.numParams = NOT_APPLICABLE;
                        $$.returnType = NOT_APPLICABLE;
                    }
                }
            }
            ;

if 语句显然现在不起作用,但我只需要能够查看它是有理运算符还是算术运算符等。

稍后我还需要能够使用一种产品,因此请说以下内容:

N_PROGN_OR_USERFUNCTCALL : N_FUNCT_NAME N_ACTUAL_PARAMS
            {

            }
            | T_LPAREN N_LAMBDA_EXPR T_RPAREN N_ACTUAL_PARAMS
            {

            }
            ;
N_FUNCT_NAME        : T_PROGN
            {

                //Change type of N_PROGN_OR_USERFUNCTCALL based off of the function return type of T_PROGN

            }

根据 T_PROGN 的返回类型,我需要能够更改 N_PROGN_OR_USERFUNCTCALL 的类型,最好的方法是什么?谢谢!

4

1 回答 1

0

关键字(一般意义上,包括和等运算符)最常见的样式><=使每个关键字都成为唯一的终端标记。在某些情况下,这会导致语法中出现一定量的重复,但它避免了扫描器和解析器之间的过度依赖。所以这是一个平衡的行为。

如果您想将具有不同语义的两个关键字合并到一个终端中,您可以通过将终端的语义类型设置为enum(或道德等价物)并在词法分析器中设置它来实现。但是您也可以在语法中组合两个关键字。

以下所有内容都有其用例,并且它们实际上并没有那么不同:

合并终端:

 // Scanner patterns
"<="       yylval.op = OP_LE; return T_BINOP;
"<"        yylval.op = OP_LT; return T_BINOP;
"+"        yylval.op = OP_PLUS; return T_BINOP;
 // etc.

 // grammar
%token <opcode> T_BINOP

%%

expr: T_BIN_OP expr expr {
        switch ($1) {
          case OP_LT: case OP_LE: case OP_EQ: ... {
            if (check_compare($2, $3)) {
              $$ = (TypeInfo){ .type = BOOL,
                               .numParams = NOT_APPLICABLE,
                               .returnType = NOT_APPLICABLE };
            else {
              yyerror(...);
            }
            break
          case OP_PLUS: case OP_MINUS: case OP_TIMES: ...
            if (check_arith($2, $3)) { 
              // ...

个别终端:

 // Scanner patterns
"<="       return OP_LE;
"<"        return OP_LT;
"+"        return OP_PLUS;
 // etc.

 // grammar
%token OP_LE "<=" OP_LT "<" 
       OP_PLUS "+"
       ...

%%

expr: "<=" expr expr {
        if (check_compare($2, $3)) {
          $$ = (TypeInfo){ .type = BOOL,
                           .numParams = NOT_APPLICABLE,
                           .returnType = NOT_APPLICABLE };
        else {
          yyerror(...);
        }
    | "+" expr expr {
        if (check_arith($2, $3)) {
          $$ = (TypeInfo){ .type = BOOL,
                           .numParams = NOT_APPLICABLE,
                           .returnType = NOT_APPLICABLE };
        else {
          yyerror(...);
        }
    // ...

或者,替代语法:

%token OP_LE "<=" OP_LT "<" 
       OP_PLUS "+" OP_TIMES "*"
       ...
%type <opcode> cmp_op arith_op ...
%%
cmp_op: "<="  { $$ = OP_LE; }
      | "<"   { $$ = OP_LT; }
      // ...
arith_op: "+" { $$ = OP_PLUS; }
        | "*" { $$ = OP_TIMES; }
        // ...
expr: cmp_op expr expr {
        if (check_compare($2, $3)) {
          $$ = (TypeInfo){ .type = BOOL,
                           .numParams = NOT_APPLICABLE,
                           .returnType = NOT_APPLICABLE };
        else {
          yyerror(...);
        }
    | arith_op expr expr {
        if (check_arith($2, $3)) {
          $$ = (TypeInfo){ .type = BOOL,
                           .numParams = NOT_APPLICABLE,
                           .returnType = NOT_APPLICABLE };
        else {
          yyerror(...);
        }
    // ...

注意:以上都没有真正保存仔细计算的操作码,也没有参数。但是,问题中的代码也没有。但这些都没有显着不同的版本。


老实说,我不确定您的第二个问题是什么意思。“N_PROGN_OR_USERFUNCTCALL 的类型”是什么?您的意思是您设置为typeTYPE_INFO成员的值的枚举吗?还是您的意思是您可能希望 N_PROGN_OR_USERFUNCTCALL 成为不止一种可能的语义类型?在后一种情况下,您需要重新考虑您的设计。在这方面,Bison/yacc 与 C 具有完全相同的语义;变量的类型是变量的类型,您无法在运行时决定xint还是double。非终结符是变量的语法等价物,每个非终结符都有一个预先声明的类型。如果您需要更多替代方案,可以使用有区别的联合(或std::variant,在 C++ 中),就像使用底层实现语言一样。(一个有区别的联合是一个struct包含一个类型枚举和一个union不同类型的值。)

于 2021-10-15T20:12:15.423 回答