Bison 解析语义值

Bison parsing semantic values

我有下面的代码,我正在验证匹配类型。例如,关系操作仅使用布尔类型执行。我已经得到了大部分。我知道 $$ 是操作的结果, $n 是右手。但是当我将它应用于函数头时我很困惑,我需要确保指定的 return 类型正在被 returned。根据我下面的语法,return 类型将是 $5,但 returned 的实际值应该是 $$。我的问题是我将它应用到语法的正确部分吗?关于如何验证该函数是正确的类型,我的逻辑是否正确?return?

%{

#include <string>
#include <vector>
#include <map>

using namespace std;

#include "types.h"
#include "listing.h"
#include "symbols.h"

int yylex();
void yyerror(const char* message);

Symbols<Types> symbols;
vector<Types> case_statements;
%}

%define parse.error verbose

%union
{
    CharPtr iden;
    Types type;
}

%token <iden> IDENTIFIER
%token <type>INT_LITERAL REAL_LITERAL BOOL_LITERAL NOTOP CASE CASES TRUE FALSE ELSE ENDIF IF

%token ADDOP MULOP RELOP ANDOP EXPOP OROP REMOP
%token BEGIN_ BOOLEAN END ENDREDUCE INTEGER IS FUNCTION REDUCE RETURNS ENDCASE OTHERS REAL THEN WHEN ARROW


%type <type> type function_header statement statement_ reductions expression binary exponent unary relation term factor primary case cases

%%

function:   
    function_header optional_variable body;
    
function_header:    
    FUNCTION IDENTIFIER parameters RETURNS type ';' {checkAssignment($$,, "Narrowing Function Returns");}|
    FUNCTION IDENTIFIER RETURNS type ';' {checkAssignment($$,, "Narrowing Function Returns");}|
    error ';' ;
    

optional_variable:
    optional_variable variable |
    error ';' |
    ;

variable:   
    IDENTIFIER ':' type IS statement_ 
        {checkAssignment(, , "Variable Initialization");
        {if (symbols.find(, )) appendError(DUPLICATE_IDENTIFIER, );
        symbols.insert(, );} };

parameters:
    parameter optional_parameter;
    
optional_parameter:
    optional_parameter ',' parameter|
    ;
    
parameter:
    IDENTIFIER ':' type {symbols.insert(, );}

type:
    INTEGER {$$ = INT_TYPE;} |
    REAL {$$ = REAL_TYPE;} |
    BOOLEAN {$$ = BOOL_TYPE;} ;

body:
    BEGIN_ statement_ END ';' ;
    
statement_:
    statement ';' |
    error ';' {$$ = MISMATCH;} ;
    
statement:
    expression |
    REDUCE operator reductions ENDREDUCE {$$ = ;} ; |
    IF expression THEN statement_ ELSE statement_ ENDIF {$$ = checkIfThen($$, , );} |
    CASE expression IS cases OTHERS ARROW statement_ ENDCASE {$$ =checkExpression(); case_statements.push_back();
    int size = case_statements.size();
    if (!case_statements.empty()) {
        int org;
        for (int i = 0; i < size; i++){
            for (int j = 0; j < case_statements.size(); j++) {
                if (org == j) {
                    $$ = checkCases(case_statements[i], case_statements[j]);
                }
            }
            org = i;
        }
    case_statements.clear();
    }
    } ;

operator:
    ADDOP |
    RELOP |
    EXPOP |
    MULOP ;

cases:
    | cases case {$$ = ;} ;

case:
    WHEN INT_LITERAL ARROW statement_ { case_statements.push_back();} ;
    

reductions:
    reductions statement_ {$$ = checkArithmetic(, );} |
    {$$ = INT_TYPE;} ;

expression:
    expression OROP binary {$$ = checkLogical(, );} |
    binary ;

binary:
    binary ANDOP relation {$$ = checkLogical(, );} |
    relation

relation:
    relation RELOP term {$$ = checkRelational(, );}|
    term ;

term:
    term ADDOP factor {$$ = checkArithmetic(, );} |
    factor ;
      
factor:
    factor MULOP primary  {$$ = checkArithmetic(, );} |
    factor REMOP exponent {$$ = checkInteger(, );} |
    exponent ;

exponent:
    unary |
    unary EXPOP exponent {$$ = checkArithmetic(,);};

unary:
    NOTOP primary {$$ = ;}|
    primary;

primary:
    '(' expression ')' {$$ = ;} |
    INT_LITERAL |
    REAL_LITERAL |
    IDENTIFIER {if (!symbols.find(, $$)) appendError(UNDECLARED, );} ;
    
%%

void yyerror(const char* message)
{
    appendError(SYNTAX, message);
}

int main(int argc, char *argv[])    
{
    firstLine();
    yyparse();
    lastLine();
    return 0;
} 

编辑:根据以下信息更新了代码

function:   
    function_header optional_variable body {checkAssignment(,, "Narrowing Function Return");};;
    
function_header:    
    FUNCTION IDENTIFIER parameters RETURNS type ';' {$$ = ;} ;|
    FUNCTION IDENTIFIER RETURNS type ';' {$$ = ;} ;|
    error ';' {$$ = MISMATCH;};
    

optional_variable:
    optional_variable variable |
    error ';' |
    ;

variable:   
    IDENTIFIER ':' type IS statement_ 
        {checkAssignment(, , "Variable Initialization");
        {if (symbols.find(, )) appendError(DUPLICATE_IDENTIFIER, );
        symbols.insert(, );} }

parameters:
    parameter optional_parameter;
    
optional_parameter:
    optional_parameter ',' parameter|
    ;
    
parameter:
    IDENTIFIER ':' type {symbols.insert(, );}

type:
    INTEGER {$$ = INT_TYPE;} |
    REAL {$$ = REAL_TYPE;} |
    BOOLEAN {$$ = BOOL_TYPE;} ;

body:
    BEGIN_ statement_ END ';' {$$ = ;}
    
statement_:
    statement ';' {$$ = ;}|
    error ';' {$$ = MISMATCH;} ;
    
statement:
    expression {$$ = ;}|
    REDUCE operator reductions ENDREDUCE {$$ = ;} ; |
    IF expression THEN statement_ ELSE statement_ ENDIF {$$ = checkIfThen(, , );} |
    CASE expression IS cases OTHERS ARROW statement_ ENDCASE {$$ =checkCaseExpression();case_statements.push_back();
    int size = case_statements.size();
    if (!case_statements.empty()) {
        int org;
        for (int i = 0; i < size; i++){
            for (int j = 0; j < case_statements.size(); j++) {
                if (org == j) {
                    $$ = checkCases(case_statements[i], case_statements[j]);
                }
            }
            org = i;
        }
    case_statements.clear();
    };} ;

operator:
    ADDOP |
    RELOP |
    EXPOP |
    MULOP ;

cases:
    %empty {$$ = EMPTY; }|
    cases case ;

case:
    WHEN INT_LITERAL ARROW statement_ { case_statements.push_back();}|
    %empty {$$ = EMPTY;} ;

检查器功能

void checkAssignment(Types lValue, Types rValue, string message)
{
    if (lValue != MISMATCH && rValue != MISMATCH && lValue != rValue)
        appendError(GENERAL_SEMANTIC, "Type Mismatch on " + message);
}

每个语法符号(记号或 non-terminal)都有一个关联的“语义”值。 “语义”一词用于表示这些值不是句法的;也就是说,它们不是解析的一部分。 bison/yacc 解析器不会为您计算这些值,因为它只关心解析输入。但是,它确实安排了两件事:

  • 词法分析器设置的语义值与对应的token关联;
  • 任何与产生式(“语义动作”)相关联的代码都会在该产生式被识别时执行。

您可以编写语义动作来计算那些 non-terminal 其语义值在使用它们的产品中需要的语义值。您可以通过 * 分配给特殊符号 $$ 来做到这一点,解析器将使用它作为产生式已被识别的 non-terminal 的语义值

在一个语义动作中,可以引用产生式right-hand端文法符号的语义值,使用特殊符号</code>、<code>等. 数字是 right-hand 边上符号的索引。如果那个符号是一个记号,它的值一定是由词法扫描器设置的,通过放入yylval。如果引用的符号是 non-terminal,则该值必须由 every 产品为 non-terminal 设置(其操作必须将一些值分配给 $$ .

Bison 手册中有一章是关于 Language semantics 的,其中包含更多详细信息和示例。 (如果您还没有阅读该手册中的介绍性内容 material,可能会有所帮助。)

就其价值而言,我建议不要在解析期间尝试执行 type-checking。您可能会发现 分离关注点 更容易,方法是在解析期间构建语义树 ("AST"),然后对该树进行单独传递以完成分析。