我们现在开始设计数据结构:
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