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

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

使用bison和yacc制作脚本语言(4)的更多相关文章

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

    使用bison和yacc制作脚本语言(1) 环境: 环境 windows 10 Cygwin64 语言 C 工具 mingw bison flex 主要是使用bison和flex这两个软件,编译器无所 ...

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

    我们先来想一下语法 一般脚本语言不需要定义类型直接在赋值的时候确定 我们主要考虑一下变量的类型 a = 1; b = 1.1; c = "str"; 一般来讲,我们使用这三种类型, ...

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

    我们现在已经可以写好文法了,下一步我们打算开始正式创建工程了 在工程目录下,我们创建如下文件夹 ./include ./memory ./ms include文件夹下我们将放头文件 memory是内存 ...

  4. [Java面试九]脚本语言知识总结.

    核心内容概述 1.JavaScript加强,涉及到ECMAScript语法.BOM对象.DOM对象以及事件. 2.Ajax传统编程. 3.jQuery框架,九种选择器为核心学习内容 4.JQuery ...

  5. Perl,Python,Ruby,Javascript 四种脚本语言比较

    Perl 为了选择一个合适的脚本语言学习,今天查了不少有关Perl,Python,Ruby,Javascript的东西,可是发现各大阵营的人都在吹捧自己喜欢的语言,不过最没有争议的应该是Javascr ...

  6. JAVA平台上的网络爬虫脚本语言 CrawlScript

    JAVA平台上的网络爬虫脚本语言 CrawlScript 网络爬虫即自动获取网页信息的一种程序,有很多JAVA.C++的网络爬虫类库,但是在这些类库的基础上开发十分繁琐,需要大量的代码才可以完成一 个 ...

  7. Shell简介:1分钟理解什么是Shell 脚本语言 解释器 以及编译器和编译语言

    Shell简介:1分钟理解什么是Shell 脚本语言 解释器 以及编译器和编译语言 现在我们使用的操作系统(Windows.Mac OS.Android.iOS 等)都是带图形界面的,简单直观,容易上 ...

  8. PCB 规则引擎之脚本语言JavaScript应用评测

    世界上没有好做的软件,觉得好做,只是你的系统简单而已,而不是哪个行业简单,特别像我们PCB制造企业务逻辑的很复杂的,仅仅靠决策树中的每个节点布置决策逻辑是不能满足要求的,所以我们在制作PCB规则引擎必 ...

  9. Procomm Plus 与ASPECT脚本语言在基于远程终端设备上的测试应用

    产测 ---------------------------------------------------- 原文:http://www.bixuanzl.com/20180801/1084478. ...

随机推荐

  1. 【Leetcode】【Medium】Linked List Cycle II

    Given a linked list, return the node where the cycle begins. If there is no cycle, return null. 解题: ...

  2. win10系统 WMI Provider Host cpu 占用过高

    今天上班,发现系统有点卡,QQ总是没响应. 打开任务管理器,发现有一个程序- WMI Provider Host 占用cpu竟然高达80% 然后通过事件查看器发现是一个pid为9832的程序造成的 然 ...

  3. Heka配置讲解

    基于Heka,ElasticSearch和Kibana的分布式后端日志架构 目前主流的后端日志都采用的标准的elk模式(Elasticsearch,Logstash,Kinaba),分别负责日志存储, ...

  4. 如何跟踪比特币SV(BSV)地址余额?

    Coin Balance Tracker 能够查看任何BSV/BCH/BTC地址的当前余额.您只需要确保你的电脑能连接Internet以及地址正确.此程序非常安全,因为它只使用公共数据,不需要登录和密 ...

  5. ResNet 修改

    https://github.com/tornadomeet/ResNet apache 开源项目 修改如下: 训练模块 import argparse,logging,os import mxnet ...

  6. 在.Net项目中使用Redis作为缓存服务

    转自:http://www.cnblogs.com/hohoa/p/5771255.html 最近由于项目需要,在系统缓存服务部分上了redis,终于有机会在实际开发中玩一下,之前都是自己随便看看写写 ...

  7. ASP.NET Core 程序发布到Linux(Centos7)爬坑实战

    前言 前阶段弄了个Linux系统想倒腾倒腾.NET Core,结果看了下网上的资料,大部分都是过期的,走了不少弯路,不过还好,今下午总算捣鼓出来了.Linux命令太多了,唉.血的教训:安装一定要看官网 ...

  8. argsort

    argsort函数返回的是数组值从小到大的索引值One dimensional array:一维数组 >>> x = np.array([3, 1, 2]) >>> ...

  9. 隐藏C#的TabControl控件的选项卡TabPage

    在使用TabControl控件时,希望隐藏其中某个选项卡(即TabPage).TabPage类明明提供了一个Hide方法,用在代码中却没有任何效果,甚是奇怪.无奈之余,只好考虑另辟途径.方法一:设置该 ...

  10. spring AOP 代理(静态与动态+使用cglib实现)

    一.没有代理模式 缺点: 1.工作量特别大,如果项目中有多个类,多个方法,则要修改多次. 2.违背了设计原则:开闭原则(OCP),对扩展开放,对修改关闭,而为了增加功能把每个方法都修改了,也不便于维护 ...