使用bison和yacc制作脚本语言(4)

我们现在开始设计数据结构:

interpreter.h

#ifndef INTERPRETER
#define INTERPRETER

#include "../include/eval.h"

typedef struct interpreter_tag Interpreter;

struct interpreter_tag
{
    MEM_Storage storage;//存储器
    MEM_Storage charpool;
    Statement_list *list;//语句表
    Function_t *functionlist;//函数表
    Environment globalEnvironment;//全局变量存放的位置
};
Interpreter *getInterpreterInstance();
void *Interpreter_malloc(int size);//使用存储器分配内存
char *Interpreter_str_malloc(char *str);//分配字符串

#endif

Interpreter就是解释器的结构体,存放一些全局信息,在需要的时候可以通过getInstance获取实例

我们的解释器执行的时候是先使用yylex构建抽象语法树(AST),然后再解释执行

我们先来看一下语句的结构体:

struct Statement_tag
{
    enum StatementType type;
    union {
        ExpressionStatement *e;//表达式语句
        For_Statement *f;//for语句
        If_Statement *i;//if 语句
    } u;
};

我们把表达式语句,if和for语句放在一个联合体中,通过type来区分不同的联合体,比直接使用void*更方便

表达式语句中存放一个表达式

struct Expression_Statement_tag
{
    Expression *expression;
};

表达式也和语句一样,使用type来区分指针

struct Expression_tag
{
    enum Expression_type type;
    Expression_u u;
};
union Expression_uni {
    PrimaryExpression *p;//这个主要跟文法中primary_expresison对应
    Binary_Expression *b;//主要跟二元操作对应,比如add sub mul div eq ne
    Assign_Expression *a;//赋值表达式
    Expression *e;//表达式指针
    FuncCallExpression *func;//函数表达式
};

我们先来看primaryexpression结构体,里面同理里使用枚举来确定联合体里面保存的变量类型

struct PrimaryExpression_tag
{
    enum ValueType type;
    union {
        int i;
        double d;
        // char *str;
        MString*mstring;
        char *identifier;
    } u;
};

注意其中mstring是由引用计数管理的字符串指针

Expression *create_IntergerExpression(int i);//创建一个整数表达式
Expression *create_DoubleExpression(double i);//创建一个浮点数表达式
Expression *create_StrExpression(char *p);//创建一个字符串表达式
Expression *create_IDExpression(char *p);//创建一个identitier表达式
Binary_Expression *createBinaryExpression(enum ExpressionAction action, Expression *left, Expression *right);//二元表达式
Assign_Expression *createAssignExpression(char *c, Expression *expression);//赋值表达式
Expression *binExpressionWarpper(Binary_Expression *expression);//二元表达式包装为Expression
Expression *AssignExpressionWarpper(Assign_Expression *expression);//赋值
Expression *create_FuncCallExpression(char *identifier, ParamList *params);//创建函数

这些函数是各个表达式创建函数我们可以在bison语法文件 m.y中使用这些函数

这里拿 primaryexpression举例

primary_expression:SUB primary_expression
        {
                $$=$2;
        }
        |LP expression RP
        {
                $$=$2;
        }
        |IDENTIFIER
        {
                $$=create_IDExpression($1); 
        }
        |STRING_LITERAL
        {
                $$=create_StrExpression($1); 
        }
        |INT_LITERAL
        {
                $$=create_IntergerExpression($1);
        }
        |DOUBLE_LITERAL
        {
                $$=create_DoubleExpression($1);
        }
        |IDENTIFIER LP RP
        {
                $$=create_FuncCallExpression($1,NULL);
        }
        |IDENTIFIER LP arglist RP
        {
                $$=create_FuncCallExpression($1,$3);
        }
        ;

$$代表是将会压入栈中的变量,$n是代表当前参与规约的第n个元素,比如IDENTIFIER LP arglist RP中$1代表IDENTIFIER,$3代表arglist

当使执行规约的时候会自动执行action{},最后形成抽象语法树把各个表达式连接起来

如果我们不给$$赋值,那么将会把$1压入栈

%union {
    char                *identifier;
    Expression          *expression;
    int integer;
    double db;
    Statement*statement;
    Statement_list*statement_list;
    Function_t*function;
    ParamList*paramlist;
}

这个联合体声明就是终结符和非终结符的类型

终结符和非终结符类型可以选择声明

%token表示终结符,%type表示非终结符

%token <integer> INT_LITERAL
%type <statement_list> block statement_list

语句最后会被规约单个语句

代码已经上传至github地址:https://github.com/stdpain/compiler-interpreter

可以看一下create.c 和 ms.y

posted @ 2019-03-14 11:48  stdpain  阅读(461)  评论(0编辑  收藏  举报