前言
这是之前在掘金发的两条沸点,懒得写了,直接复制过来作为前言了。然后这个项目可能之后还会继续写,增加一些路由或者模板引擎的指令什么的,但是再过没多久寒假就有大块时间了就可能不摸这个鱼去开其它坑了,随缘吧。所以先写JSX的解析器吧,这个部分也比较独立
掘金沸点里有一些代码截图,就不发在markdown里
算是利用期末考这段碎片时间摸一个水项目吧
项目地址:
这是之前在掘金发的两条沸点,懒得写了,直接复制过来作为前言了。然后这个项目可能之后还会继续写,增加一些路由或者模板引擎的指令什么的,但是再过没多久寒假就有大块时间了就可能不摸这个鱼去开其它坑了,随缘吧。所以先写JSX的解析器吧,这个部分也比较独立
掘金沸点里有一些代码截图,就不发在markdown里
算是利用期末考这段碎片时间摸一个水项目吧
项目地址:
在之前的名字、作用域那篇提到模块类型,它使程序员可以从一个给定抽象出发,通过实例化产生多个实例;再后面是类,它使程序员可以定义一族相关的抽象。
在这一篇里,我们会来看一下面向对象程序设计及其三个基本概念、动态方法约束、多重继承等等
随着软件变得越来越复杂,数据抽象已经变成了软件工程中最重要的部分。由模块和模块类型提供的这种抽象至少带来了如下三个好处:
在之前我们把抽象定义为一种过程,程序员可以通过它将一个名字与一段可能很复杂的程序片段关联起来。抽象最大的意义就在于,我们可以从功能和用途的角度来考虑它,而不是实现。
在大多数程序设计语言中,子程序是最主要的控制抽象的方法。大多数子程序都是参数化的,即通过传递一些参数来影响子程序的行为。
当一个子程序被调用的时候,在栈的顶部将给它一个新的栈帧或称为活动记录。这个栈帧可能包含实际参数和/或返回值、簿记信息(包含返回地址和保存的寄存器)、局部变量和/或各种临时量。当子程序返回时,栈帧从栈中弹出。
如果某个对象的大小在编译时位置,那么就将它放在栈帧的顶部大小可变的区域,并将它的地址和内情向量保存在栈帧的某个部分,放在相对于栈指针的一个静态可知的偏移处。
这两篇写了词法分析和语法分析,比较偏向实践。这一篇来看一下语言设计里一个比较重要的部分:名字。在大部分语言里,名字就是标识符,如果从抽象层面来看名字就是对更低一级的内存之类的概念的一层抽象。但是名字还有其它相关的比如它的约束时间和生存周期等等
约束就是两个东西之间的一种关联,例如一个名字和它所命名的事物,约束时间就是指创建约束的时间。有关的约束可以在许多不同的时间作出
这就是为什么基于编译的语言实现通常会比基于解释器的语言的实现更高效的原因,因为基于编译的语言在更早的时候就做了约束,比如对于全局变量在编译时就已经确定了它在内存中的布局了
虽然标题是程序语言的语法,但是讲的是对词法和语法的解析,其实关于这个前面那个写编译器系列的描述会更清楚,有关语言语法的部分应该是穿插在整个设计当中的,也看语言设计者的心情了
和英语汉语这些自然语言不一样,计算机语言必须是精确的,它们的语法和语义都必须保证没有歧义,这当然也让语法分析更加简单
所以对于编译器一项很重要的任务就是时别程序设计语言的结构规则,要完成这个目标就需要两个要求:
第一个要求主要由正则表达式和上下文无关文法来描述完成,而第二个要求就是由编译器来完成,也就是语法分析了
对于词法,都可以用三种规则描述出来: