SchemeInterpreterJava
整个项目使用Java语言编写,用于解释执行Scheme语言,本项目不会过多做很多人性化的功能,比如输入一个文件,分析一个scheme文件等等,
不存在的。项目clone下来以后使用IntelliJ运行,
直接在console里面输入scheme语句就可以进行解释执行
基本配置
IntelliJ IDEA
Java 8
疑难点记录
语法分析阶段和运行时阶段
对于这两个阶段,在编程的时候,经常会进行混淆,就是到底该什么时候检查类型
错误,比如如下语句
(define a 1)
不用怀疑,是正确的。
但是如果出现了下面的语句
(define a (define b 1))
明显是不正确的,这里就需要考虑在哪里检查这个错误,针对这个问题,有一个
很好的知道方针,装逼点说就是“上下文无关语法”,通俗点说就是语法分析阶段
要进行检查的仅仅只有这条语句满不满足正则表达式即可。
上面的
(define a (define b 1))
是符合正则表达式的,所以语法阶段是允许通过的,但是会出现运行时错误。
编程时要时刻注意,时刻用这个方针指导自己
(define)和(set!)的返回值问题
2017.10.25记录
这个问题本身我纠结了很久,就是define和set!究竟有没有返回值,以及
如果有,该如何定义,这里目前没有想到什么好的方法,我觉得只能进行
特殊处理。
存在以下代码
(define a (define a 1))
运行是会出错的,因为define没有返回值,但是如果出现了这种代码
(define a (void))
a
即执行define操作,然后在输入a,那么command-line中会什么都没有
,直接等待下面的执行,然后使用
(void? a)
成功执行,返回#t,所以void类型确实是真实存在的。
2017.10.27记录
今天我对这两个语句进行了如下处理,还包括之后的let和let*
让这四种语句返回值是BLOCKING,意思是阻断,此语句的返回值不能被
use。
对于SchemeQuoted的处理
自我感觉'()这种运算需要好好思考一下,如果定义如下语句
(define a 1)
(apply + '(1 2 3 a))
代码会报错,因为这里加上了点号,不会对列表里面的a进行解释了。
编程技巧
Predicate函数式接口的使用
在Parser部分的代码中,需要适当地检查一下参数的合法性,比如
(define a 1)
其中第二个参数就不能是除Atom之外的其他的Token的子类,又比如
(if (< x 1) (display 0) (display 1))
其中第二个参数就只能是Atom,或者是一个Call,或者就仅仅是一个Boolean
类型的字面量,其他的Token子类不允许出现。
所以我们可以这样设计代码
static Predicate IsDefineOrSet = e -> e instanceof SchemeDefine
|| e instanceof SchemeSet;
static Predicate IsProceOrRef = e -> e instanceof SchemeProcedure
|| e instanceof SchemeAtom;
static Predicate IsCallOrRef = e -> e instanceof SchemeCall
|| e instanceof SchemeAtom;
static Predicate IsNumber = IsCallOrRef.or(e -> e instanceof SchemeNumber);
static Predicate IsString = IsCallOrRef.or(e -> e instanceof SchemeString);
static Predicate IsBoolean = IsCallOrRef.or(e -> e instanceof SchemeBoolean);
static Predicate IsList = IsCallOrRef.and(e -> {
SchemeQuoted Quoted = e instanceof SchemeQuoted ? (SchemeQuoted) e : null;
if (Quoted == null) {
return false;
} else {
return Quoted.getContent() instanceof SchemeList;
}
});
通过设计基本的条件,以及对条件进行组合,我们可以得到逻辑清晰的
Predicate函数式接口,便于之后的编程。