C语言 返回野牛中第一个表达式的值

m4pnthwp  于 2023-04-29  发布在  其他
关注(0)|答案(1)|浏览(116)

我正在用野牛和Flex编写一个解析器来解析一个“自制”语言。该语言包含以下类型的某些常量表达式:

[OPERATOR, OPERAND1, OPERAND2]

其中,操作数可以是字符串、整数、真实的,也可以是另一个运算符表达式

[OPERATOR, [OPERATOR, OPERAND1, OPERAND2], OPERAND2]

[OPERATOR, Int1, Int2]等。
问题是我想返回主表达式的结果,它也调用了其他表达式。我已经制定了一个名为fulloperation的规则来尝试处理这个问题,但它只在操作表达式后面跟着另一个语句时有效(表达式是一种语句)。这些是我的语法规则,你可以在fulloperation规则下找到我的递归返回尝试(注意程序的开始和结束都在左右方括号之间):

%union{
IntNode intnode;
RealNode realnode;
StrNode strnode;
ExprNode * exprNodePtr;
int linenum;
}

%token <linenum> tADD 
%token <linenum> tSUB 
%token <linenum> tMUL 
%token <linenum> tDIV 
%token <strnode> tSTRING 
%token <intnode> tNUMI
%token <realnode> tNUMR 
%token tPRINT tGET tSET tFUNCTION tRETURN tIDENT tEQUALITY tIF tGT tLT tGEQ tLEQ tINC tDEC 

%type <exprNodePtr> operation;
%type <exprNodePtr> expr;
%type <exprNodePtr> fulloperation;
%start prog 

%%
prog:       '[' stmtlst ']' ;
;

stmtlst:    stmtlst stmt |
;

stmt:       setStmt | if | print | unaryOperation | expr | returnStmt
;

getExpr:    '[' tGET ',' tIDENT ',' '[' exprList ']' ']'
        | '[' tGET ',' tIDENT ',' '[' ']' ']'
        | '[' tGET ',' tIDENT ']'
;

setStmt:    '[' tSET ',' tIDENT ',' expr ']'
;

if:     '[' tIF ',' condition ',' '[' stmtlst ']' ']'
        | '[' tIF ',' condition ',' '[' stmtlst ']' '[' stmtlst ']' ']'
;

print:      '[' tPRINT ',' expr ']'
;

operation:  '[' tADD ',' expr  ',' expr']' {
                                            $$ = SumExpr($4, $6);
                                            }
        | '[' tSUB ',' expr',' expr']'{
                                            $$ = SubExpr($4, $6);
                                            }
        | '[' tMUL ',' expr ',' expr ']'{
                                            $$ = MulExpr($4, $6);
                                            }
        | '[' tDIV ',' expr ',' expr  ']'{
                                            $$ = DivExpr($4, $6);
                                            }
;   

unaryOperation: '[' tINC ',' tIDENT ']'
        | '[' tDEC ',' tIDENT ']'
;

fulloperation: 
                operation stmt{printres($1);}|
                operation {$$ = $1;}
;

    

expr:       tNUMI {$$ = makeExpressionNodeFromInt($1);}
            | tNUMR {$$ = makeExpressionNodeFromReal($1);}
            | tSTRING {$$ = makeExpressionNodeFromStr($1);}
            | getExpr | function | fulloperation {$$ = $1;} | condition
;

function:    '[' tFUNCTION ',' '[' parametersList ']' ',' '[' stmtlst ']' ']'
        | '[' tFUNCTION ',' '[' ']' ',' '[' stmtlst ']' ']'
;

condition:  '[' tEQUALITY ',' expr ',' expr ']'
        | '[' tGT ',' expr ',' expr ']'
        | '[' tLT ',' expr ',' expr ']'
        | '[' tGEQ ',' expr ',' expr ']'
        | '[' tLEQ ',' expr ',' expr ']'
;

returnStmt: '[' tRETURN ',' expr ']'
        | '[' tRETURN ']'
;

parametersList: parametersList ',' tIDENT | tIDENT
;

exprList:   exprList ',' expr | expr
;
vm0i2vca

vm0i2vca1#

对于您的语言,它看起来非常像lisp,我会选择一个树,其中每个规则创建一个节点,然后返回。
例如,对于单分支if语句:

$$ = makeIfNode($3, $6, NULL)

对于节点本身,我将使用嵌入式节点来模拟类似C++的继承,其中顶部的基节点包含一个函数指针,该指针被初始化为一个指针来计算当前节点。
例如:

struct BaseNode
{
    int (*evaluate)(struct BaseNode *);
};

对于if语句:

struct IfNode
{
    struct BaseNode base;
    struct BaseNode *condition;
    struct BaseNode *ifTrue;
    struct BaseNode *ifFalse;
};

创建if语句节点的函数:

struct BaseNode *makeIfNode(struct BaseNode *condition, struct BaseNode *ifTrue, struct BaseNode *ifFalse)
{
    struct IfNode *ifNode = malloc(sizeof *ifNode);
    // TODO: Error checking

    ifNode->base.evaluate = &evaluateIfNode;
    ifNode->condition = condition;
    ifNode->ifTrue = ifTrue;
    ifNode->ifFalse = ifFalse;

    return (struct BaseNode *) ifNode;
}

static struct BaseNode *evaluateIfNode(struct BaseNode *base)
{
    struct IfNode *ifNode = (struct IfNode *) base;

    int result = evaluate(ifNode->condition);
    if (result != 0)
    {
        return evaluate(ifNode->ifTrue);
    }
    else if (ifNode->ifFalse != NULL)
    {
        return evaluate(ifNode->ifTrue);
    }
}

全局evaluate函数接受函数指针并使用当前节点调用它:

int evaluate(struct BaseNode *base)
{
    return base->evaluate(base);
}

为所有的表达式和语句创建类似的节点结构、节点创建函数和节点求值函数,并且您的首要规则prog将简单地调用printf("Result of program: %d\n", evaluate($2));来运行所有语句和表达式并打印最终结果。

相关问题