自己去创建一个编程语言吧(5)

行求,不多说话,开干

从bison开始

咱们先定义语言要用到的几种数据类型

typedef struct YYSTYPE
{
	string vSTRING; //字符串类型
	int  vINTEGER;//整数类型
	double vDOUBLE;//double类型
	struct CompileStruct* vCompileStruct;//编译结构
	Statement* vStatement;//语法结构
} YYSTYPE;

够了,就这几种就可以了,以上类型除了定义语言中需要用的类型,这些类还要提供bison的使用类型,例如定义个函数名,就需要用的vstring类型,以上最重要的是vStatement类型,它是所有表达式,语法结构的基础类型,不管是任何表达式,在menthol解析中,都会定义为statement类型

先看在整个menthol中会用到的token

%token <vSTRING>VARIDENTIFIER 
%token <vSTRING> IDENTIFIER 
%token <vSTRING> GLOBALVARIDENTIFIER
%token <vINTEGER>NUMBER
%token <vSTRING>STRING
%token <vDOUBLE>DOUBLE
%token <vINTEGER>TRUE_KEYWORD
%token <vINTEGER>FALSE_KEYWORD
%token IF ELSE FOR BREAK  TRY EXCEPT THROW IMPORT MODULE USE
%token CONTINUE RETURN  WHILE   NULL_KEYWORD
%token POWER_OP NEQ_OP OR_OP AND_OP GE_OP LE_OP EQ_OP
%token ADD_ASSIGN SUB_ASSIGN DIV_ASSIGN MUL_ASSIGN ASSIGN_ASSIGN
%token MOD_ASSIGN AND_ASSIGN OR_ASSIGN XOR_ASSIGN 
%token SHIFT_LEFT_OP SHIFT_RIGHT_OP WMAIN  DEF  VAR  IN ARRAYSECTION DICT_OP TYPEOF CONST MMRT

从IF开始应为都是已经定要的常量字符串,所以只要标记就好,前8行都是需要定义类型的

关于Statement

这是语法解析中最重要的部分,他是所有表达是的基础类型,所有的表达是不管是if,while,for他们都是Statement 的子类型,定义如下

//Parser.h
class Statement
{
public:
	virtual void CreateCode()=0;
	virtual void AddChilder(Statement* s){}
	virtual void Release()=0;
	NodeType NType;	
	Statement():ParentNode(0),bytenumber(0),startipi(0),endipi(0),ilength(0){}
	
	Statement* ParentNode;
	int wfileaddressline;
	int bytenumber;
	string name;
	int startipi;
	int endipi;
	int ilength;
};

上述代码可以看到,有两个纯虚函数,CreateCode是每一个表达是按照各自逻辑所需要生成的代码,AddChilder,是虚函数,应为有些表达式,是有子表达式的,例如module内的内容,就是module表达式的子表达式,有些是没有的,例如定义一个var $a;这种没有任何东西,也就没有子表达式,

NodeType,表示当前的表达式是什么类型表达式,类似IF,WHILE,FOR这些,它的定义如下

enum NodeType{
	MNT_FunctionParameter,//函数参数
	MNT_FunctionParameterWithDefault,//有默认值的函数参数
	MNT_TryParameter,//try
	MNT_VarIdentIfier,//$ 局部变量
	MNT_FunctionParameterStatement,//函数参数集合
	MNT_ExpressionStatement,
	MNT_ExpressionList,
	MNT_AssignmentDefinition,
	MNT_InitializationDefinition,
	MNT_AssignmentList,
	MNT_InitializationExpression,
	MNT_InitializationList,
	MNT_BuiltinTypeDeclare,
	MNT_ArithmeticExpressionDefinition,
	MNT_IfStatement,
	MNT_WhileStatement,
	MNT_ForStatement,
	MNT_ArrayDeclare,
	MNT_DictDeclare,
	MNT_ArrayElement,
	MNT_DictElement,
	MNT_ContinueExpression,
	MNT_BreakExpression,
	MNT_FunctionDefinition,
	MNT_ReturnExpression,//return
	MNT_TryStatement,
	MNT_ThrowExpression,
	MNT_CodeBlockStatement,
	MNT_ImportPackageExpression,
	MNT_ModuleExpresson,
	MNT_ModuleFunCall,//执行函数
	MNT_ModuleFunctionDefinition,//模块内函数定义
	MNT_TernaryExpression,//三元表达式
	MNT_DictExpression,//
	MNT_FunctionCall,
	MNT_FunctionArguments,
	MNT_LogiceEpressionDefintion,
	MNT_MinusExpression,
	MNT_PlusExpression,
	MNT_Release,
	MNT_InverterExpression,
	MNT_TypeOfExpression,
	MNT_ModuleStatementList,
	MNT_ModuleDefine,//模块定义
	MNT_MainFunction,//main函数
	MNT_InstanceExpression
};

它的作用在与判断有些表达式是否合法,例如,break就不能出现在除了while,for以外的地方

我们先举个例子来说明Statement的用法,先看while的bison定义

while_statement: WHILE  '(' expression_definition ')' funciton_codeblock_statement
{
	$$ = new WhileStatement();
	$$->AddChilder($3);
	$$->AddChilder($5);
}
;

解析它的程序定义如下

class WhileStatement:public Statement{
public:
	WhileStatement();//构造
	~WhileStatement();
	void AddChilder(Statement* s);//用于往Member成员中加入子表达式
	void CreateCode();//生成代码的方式
	int GetJmpPostion();
	int GetTemplateid();
	void SetBreakPostion(int b);
	void Release();
private:
	vector <Statement*> *Member;//子成员,两个expression_definition,funciton_codeblock_statement
	int postion1;
	int postion2;
	int templateid;
	vector<int> *breakpostionvector;
};

其他的额例如if,for,module等表达式,他们的基本定义也差球不多。

这个过程会把所有的以Statement为基类的表达式按层级关系,加入到statementlist类中一个叫
CompileStructTable的变量里

vector <Statement*> *CompileStructTable;

在所有程序解析完以后,调用StatementList::CreateCode,这个会调用所有表达式子类型中CreateCode方法,生成编译后的汇编(程序定义的类似汇编的语法),然后按一定的格式存储在文件中,这个文件的存储,会在以后讲

现在从bison开始看起

1.VARIDENTIFIER,这个是定义例如参数名、变量名称这些的
VARIDENTIFIER{
	$$ =new VarIdentIfier($1);
}

当遇到VARIDENTIFIER,也就是lex中以$开头的变量,会把变量名当参数出入
VarIdentIfier 构造函数中

//Parser.cpp
VarIdentIfier::VarIdentIfier(string s){
	wfileaddressline = lineno;
	name = s;
	NType = MNT_VarIdentIfier;
}
IDENTIFIER {
	StatementList *ls = (StatementList*)parm;
	ls->AddStringConstant(string($1));
	BuiltinTypeDeclare* btd =new BuiltinTypeDeclare();
	btd->SetFunctionPointerOrModule($1,1);
	$$= btd;
 } 
2.IDENTIFIER,这个用的地方比较多,例如用来表示函数名称,包的名称,属性名称等

例如在导入一个包的时候

import aaa

aaa就是定义为IDENTIFIER

3.GLOBALVARIDENTIFIER,这个是用来定义模块中以@开头的全局变量的
//bison.y
GLOBALVARIDENTIFIER{
 	StatementList *ls = (StatementList*)parm;
	ls->AddStringConstant(string($1));
 	$$ = new VarIdentIfier((char*)$1.c_str());}
   ;

当bison被解析的时候,解析程序会和定义VARIDENTIFIER一样,但多了一步,会将全局变量名称当作字符串存入程序的数据段中作为固定数据保存,这样做的原因是在虚拟机中,程序运行时可以动态判断出模块是否具有某个全局变量

有了上面上面的基础,就可以开始一步步解析语法了

不想写了,下一节开始讲表达式解析

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 的编译器和解释器是一个很有趣的项目。你可以学习到很多关于语言技术的知识,以及如何将代码转换为机器可以理解的形式。如果你是初学者,你可以先学习一些关于编译原理的基础知识,然后再开始写代码。如果你已经有了一些编程经验,那么你可以直接开始写代码。不管你是初学者还是有经验的开发者,这都是一个很好的学习机会。 Writing a compiler and interpreter for a programming language in Go is a fun project. You can learn a lot about language technology and how to translate code into a form that machines can understand. If you're a beginner, you can start by learning some basics about compilation theory, and then start coding. If you already have some programming experience, you can jump right into coding. Regardless of whether you're a beginner or an experienced developer, this is a great learning opportunity. ### 回答2: Go语言是一种开源的静态类型编程语言,因其简洁、高效和易用的特点,被广泛应用于编写各种类型的软件。而使用Go语言编写一个编程语言本身是可以实现的。 首先,编程语言是一种规则的描述方式,它定义了一套语法规则和语义规则,用于编写可执行的计算机程序。因此,用Go语言编写编程语言实际上是通过定义一系列的词法、语法和语义规则,来构建解析和执行程序的框架。 其次,Go语言自身提供了强大的工具和库,使得编写语言解析器、编译器和虚拟机等组件变得相对容易。通过使用Go语言的语法和工具,可以方便地定义和解析具有特定语法的源代码,将其转换为可执行的二进制代码,并最终在虚拟机或计算机上运行。 在编程语言设计的过程中,需要考虑词法分析、语法分析、符号表管理、类型检查、代码生成等多个方面。使用Go语言的强类型特性,可以方便地进行类型检查和代码生成,同时Go的并发特性也为编写具有并行执行能力的编程语言提供了支持。 最后,编程语言的学习和应用是一个持续改进的过程,使用Go语言编写的编程语言也需要不断进行调试和优化。Go语言的快速编译和执行速度,以及强大的测试和性能分析工具,可以极大地提高编程语言开发效率和质量。 总之,使用Go语言编写编程语言是完全可行的,通过合理地设计和实现,可以创建出功能完备、易用高效的新编程语言。同时,借助Go语言的生态系统和工具,也可以为编程语言提供更好的开发和调试环境。 ### 回答3: 使用Go语言编写一种新的编程语言的过程需要遵循一定的步骤和规则。下面是一个简要的概述: 1. 设计语言的语法:首先,需要确定编程语言的语法结构和规则。这涉及定义关键字、变量和函数声明、控制流语句等。这个设计的目标是使语言易于理解和使用。 2. 编写词法分析器:词法分析器的作用是将源代码分解为符号或记号(tokens)的序列。每个符号代表源代码中的一个词或操作符。在Go语言中,可以使用正则表达式和字符串处理函数来实现词法分析器。 3. 编写语法分析器:语法分析器的任务是将词法分析得到的记号序列转化为抽象语法树(AST)。抽象语法树表示源代码的结构和层次,使得可以进行进一步的分析和操作。Go语言提供了一些强大的工具,如解析器生成器(parser generator)来简化语法分析器的编写。 4. 实现编译器/解释器:根据语法树生成可执行代码的过程称为编译,而将源代码行为直接解释为机器指令的过程称为解释。在Go语言中,可以使用AST作为中间表示(IR),根据IR生成目标代码或直接执行。 5. 定义标准库和扩展:一个完整的编程语言需要一个强大的标准库,提供常用的函数和工具,使得开发者可以通过调用这些库快速实现功能。此外,提供扩展语言的机制和接口,使得其他开发者可以为该编程语言编写自己的库和组件。 6. 测试和优化:在开发过程中,进行充分的测试和优化是必不可少的。编写单元测试、集成测试和性能测试来确保编程语言的正确性和性能。 尽管Go语言本身已经非常适合编写编译器和解释器,但是编写一个全新的编程语言仍然需要耗费大量的时间和精力。编程语言的设计和实现是一个复杂的过程,需要的知识和技能包括编译原理语言设计、算法和数据结构等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值