这一段时间由于要找工作,因此,如果幸运地获得面试的机会的话(现在多么不容易啊),作为一名软件工程师,我免不了要被问大量的技术性问题。但由于现在不工作,平时不用的话,这些知识很容易被大脑驱逐出主要存储区域,而转到类似“SWAP”的地方。遗憾的是,大脑不比电脑,从“SWAP”里调东西不只是慢一些的问题,而是需要极其复杂的手续,比如催眠、打坐冥想、灵机一动、状态极佳等等,都是在面试时不太现实的。因此,必须多多使用这些知识,让大脑认为它们很重要,从而调到主要的快速存储区域里去。这样才有望在面试中对答如流。
但是,作为超级现实主义的本人来说,弄一些没用的东西是对时间和生命的极大浪费。因此,我就给自己设计了一个有用的项目:做一个BASIC语言解释器,将来可以加入很多算法、统计学、金融相关的计算功能,作为一种“内嵌语言”工具来使用。经过一段时间的努力,终于初步成型。目前还达不到1.0版的要求,但已经能正常执行很多程序,并能评价各种表达式的值。
另,还有一个做该项目的原因:我在之前的工作中用到某大公司的一个系统,他们提供TCL作为可编程的借口和内嵌语言。我的工作模式是:编写各种计算程序,并将各种功能做成TCL命令,跟TCL系统结合起来。然后,就是用TCL编写脚本程序来实现公司的各种计算需求。但TCL语言是一种功能很弱的语言,不但无法评价表达式的值(必须用expr命令来评价,十分麻烦),而且其各种流程控制结构也很笨拙。其他常用的语言,比如Python,我不喜欢它对程序书写格式的限制(比如每行前面要加多少个制表符等),把它跟C++或Java语言程序集成在一起也很令人头疼;而JavaScript(Rhino)我也不喜欢。因此,我就想做一个更好的,以便将来有用。选择BASIC语言的原因,一方面是BASIC十分简单易用,而又提供足够的威力来控制流程和进行计算;另一方面,BASIC语言是我在多年前(高中时)学的第一种编程语言,可能跟比尔·盖茨似的,对它有某种感情吧。
目前的版本大约达到0.6版的程度了吧?主要功能都实现了,但还没有支持数组(多维)、日期和时间计算以及将来要加入的各种算法、统计计算和金融计算等。目前的状态也不是一个嵌入式语言,而是一个命令行BASIC解释器或命令行表达式评价程序的形式。该程序会把结果输出到stdout(标准输出设备),并返回0。如果有错误发生,则向stderr(标准错误设备)输出错误信息,并返回1。本软件为非开源的免费软件,可免费使用和传播,但禁止把它单独或作为系统的一部分销售给他人。可以在这里下载。
由于本来的目的是把它作为嵌入式语言工具使用,因此,只保留了BASIC语言中一些主要的功能(精华?),把那些陈芝麻烂谷子的糟粕通通舍弃了。同时,又从Visual Basic里借来一些新的特性(比如:函数的参数按引用传递、用RETURN返回、循环体内的CONTINUE等)。
本软件用C++(以及STL)编写,没用其他第三方软件(比如yacc等)。
该软件的使用方法:
mybasic -e <表达式>
或者
mybasic -f <BASIC程序的文件名>
演示:
演示的程序(test.bas):
function mySum (byval x as integer) as integer
if x <= 1 then
return x
else
return x + mySum(x - 1)
end if
end function
print mysum(100)
本程序的规格说明:
表达式评价
表达式以BASIC语言的语法书写。该程序支持算术、字符串、关系和逻辑运算。
数据类型
- boolean
- integer
- double
- string
运算符
- 数学运算符: ^, +(一元运算符), -(一元运算符), *, /, \, MOD, +, –
- 字符串运算符: +
- 关系运算符: =, <>, <, <=, >, >=
- 逻辑运算符: NOT, AND, OR
- 其他: (, ) (圆括号,为了改变运算符的优先级)
数学函数
abs, sign, int, sqrt, exp, log, log10, rad(角度变弧度), deg(弧度变角度), sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh, sec, csc, pi(返回圆周率), random(返回[0, 1]区间内的随机数)
字符串函数
str(num)(数字变字符串), space(n), tab(n), ltrim(str), rtrim(str), trim(str), len(str), ucase(str), lcase(str), val(str)(字符串变数字), isNumeric(str), left(str, n), right(str, n), mid(str, from, n), instr(str1, str2)(如果str1中含有str2,则返回从0开始的索引;如果没有,则返回-1。)
与BASIC语言不同的地方
- 一些函数的函数名不同。比如,不是“sqr”,而是“sqrt”。
- 字符串的索引从0开始,而不是从1开始。
- 不支持BASIC语言的类型字符(比如,“2#”表示double型的2),因为这些实在令人讨厌。。。
BASIC 解释器
本BASIC解释器支持一个实用简练的 BASIC 语法。
“实用简练的 BASIC 语法”的规格(除了上述的表达式规格以外):
支持的特性
- 注释:REM, ‘(单引号)
- 变量声明:DIM … AS …
- 条件语句(块IF):IF, THEN, ELSEIF, ELSE, END IF
- FOR循环:FOR, TO, STEP, NEXT, CONTINUE FOR, EXIT FOR
- DO循环:DO, WHILE, UNTIL, LOOP, CONTINUE DO, EXIT DO
- 函数和过程:FUNCTION, END FUNCTION, SUB, END SUB, RETURN, BYVAL, BYREF
- 输出:PRINT
- 其他:END
不支持的特性
- LET(最没用的命令。直接无视之。)
- 行号(太古老陈旧)
- GOTO(万恶之源)
- GUSUB…RETURN(太古老陈旧)
- DEF FN(太古老陈旧)
- 标签(label)(既然GOTO、GOSUB等都舍弃掉了,也就没有必要使用标签了)
- 单行的IF
- READ…DATA(太古老陈旧)
- SELECT CASE(不喜欢该语法。但又不想加入如C++的switch/case等太不一样的东西。可以用IF代替。)
- ON [ERROR] …(太古老陈旧)
- WHILE … WEND(太古老陈旧,应以更强大的 DO … LOOP 代替)
- EXIT SUB, EXIT FUNCTION(应以 RETURN 代替)
- CALL(函数有返回类型凭什么就不能像过程那样直接调用?用CALL太麻烦,去掉。)
- variant 数据类型(降低代码质量)
- 用户定义类型(比如“类”等,因为实现太麻烦,而且在短小的脚本编程中并不需要。你要写较长的脚本?那为什么不选择一种严肃的语言呢?比如Java、C++等。)
- PRINT USING(如果必要,可考虑将来加进去)
- 文件 I/O(OPEN 等。在以后的版本中会加入新的文件I/O函数)
与一般的 BASIC 的不同之处
- 变量必须声明(用DIM)之后才能使用(相当于在 VB 中总是声明“OPTIONAL EXPLICIT”。为了提高代码质量。)
- “DIM a, b, c AS DOUBLE”可以,但不支持“DIM a AS INTEGER, b AS DOUBLE”(为了提高代码质量,使程序易读)
- Boolean型和Integer型不能相互转换(为了提高代码质量)
- 函数或过程:必须声明 BYVAL 或 BYREF(没有缺省。为了提高代码质量。)
- PRINT 语句中:
- “,”意思是插入制表符,而不是从某一列开始打印(原来的规格太古老陈旧,已不适用于今天的使用环境)
- “;”意思是紧接着上次的地方打印。这跟原规格相同,但不会在数字前自动插入一个空格(必要时,程序员应该负责做这项工作)
尚未支持的特性(会在将来的版本中支持)
- 数据类型
- 数组(多维)
- 数组的下标总是从0开始
- 在“DIM A(N) AS INTEGER”语句中,N 是指数组的大小,不是最大下标(最大下标为 N – 1)
- date
- time
- datetime
- 内置函数
- 一些统计类函数
- 一些数值算法
- 文件 I/O
- 其他的互操作性(?)
- 命令