打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
用C++实现了一个迷你的lisp解释器

用C++实现了一个迷你的lisp解释器

找出需求和现存实现的相同部分 - 交;将这些部分加入程序中 - 并;然后慢慢打补丁吧。

前两天和mayadong说到lisp,想起很久以前看过的一篇文章《Lisp之根源》(http://daiyuwen.freeshell.org/gb/rol/roots_of_lisp.html)。当时看得似懂非懂,于是想找来再看看。
搜到文章以后,从头到尾看了一遍,基本上算是看懂了。文章中的lisp只有lambda, label以及7个原始操作符。而这种lisp的有趣之处是它可以实现一个函数作为解释自己的解释器。不过这个解释器并不是解释字符形式的源码,而是解释表示lisp程序的表。看完文章后,我突然想,如果用C++实现一个这样的解释器如何呢?
分析了一下,觉得应该不是很困难。在这几天找了些时间,做了这么一个东西。这个解释器相当简陋,甚至没有出错的处理,如果lisp程序有错,要么就没有任何反应,要么解释器本身就会挂掉。而且只能解释在《Lisp之根源》中说的那种lisp语言。所以冠之“迷你”以解嘲。
其实用C++写解释器程序到没费太大的劲,只是用lisp测试时把我累坏了。lisp这语言真不是盖的,括号稀里哗啦一大堆,看得我眼花缭乱。

为了输出结果,增加了一个print函数。

用法:
可以把lisp源程序作为参数传递给程序minilisp。如果没有参数,minilisp将试图执行test.lsp。
比如,有一个subst.lsp文件:
(defun subst (x y s) ; 函数subst用x替换s中所有的y
  (cond
    ((atom s) (cond
                 ((eq s y) x)
                 ('t       s)))
    ('t        (cons (subst x y (car s))
                      (subst x y (cdr s))))))
(label s '(Hello this (no any Hello) word))
(print (subst 'Hi 'Hello s))

F:\Projects\minilisp>minilisp subst.lsp
(Hi this (no any Hi) word)

源程序,可执行文件,及测试lisp程序,可以在这儿下载
http://code.google.com/p/scriptdraw/downloads/detail?name=minilisp.zip&can=2&q=#makechanges
备用地址 http://115.com/file/aq5fib2x#

不想下载的,可以直接看下面的源程序:

#include <iostream>
#include <fstream>
#include <string>
#include <map>
using namespace std;

#include <assert.h>

typedef string* Atom;
// Cell为链表的节点,Cell*对应lisp中的表
struct Cell {
    void* first; // 节点的第一个元素,是一个原子(Atom)或一个链表(Cell*)
    Cell* rest;
};
// 解析结果
struct Result {
    const char* tail; // 没有解析的源码位置
    void* parsed;     // 解析出的内容
    Result(const char* r, void* p) : tail(r), parsed(p) {}
};
typedef map<Atom, void*> Environment; // 包含各种变量的环境
// ------ Atom ------
const int MAX_ATOMS = 4096; // 最大原子数
string* atomTable;          // 所有原子存放在一个统一的表中
string* lastAtom;           // 最后一个原子的位置

map<string, Atom> atomDict; // 原子字典,根据字符串查找对应的原子

Atom atomTrue, atomLambda, atomQuote; // 解释器中用到的原子
bool isCell(void* p);                 // 指针p是否指向一个Cell
void gc(Environment& env);            // 进行垃圾收集
void* gcAlloc(size_t size);           // GC方式分配内存

// 创建一个原子
Atom createAtom(const string& sym) {
    if(atomDict.find(sym) == atomDict.end()) { // 如果在字典中没有这个原子
        if(lastAtom < atomTable + MAX_ATOMS) { // 原子表中还有空位
            *lastAtom = sym;                   // 加入原子表中
            atomDict[sym] = lastAtom;          // 放入原子字典
            ++ lastAtom;
            return lastAtom - 1;
        } else {
            return 0; // 原子溢出,简单起见,不处理
        }
    }
    return atomDict[sym]; // 在原子表中已存在该原子,直接返回
}
// p 是否是一个原子
bool isAtom(void* p) {
    return atomTable <= p && p <= atomTable + MAX_ATOMS;
}
// 创建一个lisp中的表
Cell* cons(void* fst, Cell* rst) {
    Cell* c = (Cell*)gcAlloc(sizeof(Cell));
    c->first = fst;
    c->rest  = rst;
    return c;
}
// ------ Parser ------
Result parseList(const char* p);
Result parseAtom(const char* p);
bool isAtomChar(char ch);
bool isBlank(char ch);
const char* skipBlanks(const char* p);
// 解析源码p
Result parse(const char* p) {
    p = skipBlanks(p); // 跳过空白
    if(*p == '(') {    // 如果是(,解析表
        return parseList(p+1);
    } else if(*p == '\'') { // '表示quote
        Result r = parse(p+1);
        return Result(r.tail, cons(atomQuote, cons(r.parsed, 0)));
    } else if(isAtomChar(*p)) { // 如果是组成原子的字符
        return parseAtom(p);
    }
    return Result(p, 0);
}
// 解析原子
Result parseAtom(const char* p) {
    const char* q = p;
    while(isAtomChar(*q)) {
        ++q;
    }
    return Result(q, createAtom(string(p, q)));
}
// 解析表
Result parseList(const char* p) {
    p = skipBlanks(p);
    if(*p == ')') { // 表结束了,返回一个空表()
        return Result(p+1, 0);
    }
    Result rfirst = parse(p); // 解析表中的第一个元素
    Result rrest = parseList(rfirst.tail); // 解析其它元素
    return Result(rrest.tail, cons(rfirst.parsed, (Cell*)rrest.parsed)); // 将两者构造成一个表
}
// 除'(' ')'和空白外都是原子字符
bool isAtomChar(char ch) {
    return ch != '\0' && ch != '(' && ch != ')' && !isBlank(ch);
}
// 空格、制表符、换行符等都是空白字符
bool isBlank(char ch) {
    return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\r' || ch == '\n';
}
// 跳过空白,返回值为p的非空白的开始位置
const char* skipBlanks(const char* p) {
    while(isBlank(*p))
        p++;
    return p;
}

// ------ evaluate -------
typedef void* (*PrimeFunc)(Environment* env, Cell* args);
const int MAX_LAMBDAS = 2048;

void* evalExpression(Environment* env, Cell* expr);
void* evalValue(Environment* env, void* v);
// 输出原子和表
void print(void* x) {
    if(x == 0) {
        cout << "()"; // 空表
    } else if(isAtom(x)) { // 原子
        Atom atom =(Atom)x;
        cout << *atom;
    } else { // 表
        cout << "(";
        Cell* cell = (Cell*)x;
        while(cell) {
            print(cell->first);
            cell = cell->rest;
            if(cell) {
                cout << " ";
            }
        }
        cout << ")";
    }
}
// 参数为表达式的函数
// 表达式直接传递给函数,不进行求值
// quote, lambda, label, cond, defun对应的C++函数
void* primeQuote(Environment* env, Cell* args) {
    return args->first;
}
void* primeLambda(Environment* env, Cell* args) {
    return cons(atomLambda, args);
}
void* primeLabel(Environment* env, Cell* args) {
    if(isAtom(args->first)) {
        Atom nameAtom = Atom(args->first);
        (*env)[nameAtom] = evalValue(env, args->rest->first);
    }
    return 0;
}
void* primeCond(Environment* env, Cell* args) {
    Cell* c = args;
    while (c != 0) {
        if(isAtom(c->first)) break; // error!
        Cell* pair = (Cell*)(c->first);
        if(evalValue(env, pair->first) != 0) {
            return evalValue(env, pair->rest->first);
        }
        c = c->rest;
    }
    return 0;
}
void* primeDefun(Environment* env, Cell* args) {
    Cell* lam  = cons(atomLambda, args->rest);
    void* name = args->first;
    return primeLabel(env, cons(name, cons(lam, 0)));
}
// 参数为值的函数
// 表达式求值后,将值传递给函数
// print, car, cdr, cons...对应的函数
void* primePrint(Environment* env, Cell* args) {
    print(args->first);
    if(args->rest) {
        cout << " ";
        primePrint(env, args->rest);
    }
    cout << endl;
    return 0;
}
void* primeFirst(Environment* env, Cell* args) {
    if(args->first && !isAtom(args->first)) {
        Cell* arg1 = (Cell*)(args->first);
        return arg1->first;
    }
    return 0;
}
void* primeRest(Environment* env, Cell* args) {
    if(args->first && !isAtom(args->first)) {
        Cell* arg1 = (Cell*)(args->first);
        return arg1->rest;
    }
    return 0;
}
void* primeCons(Environment* env, Cell* args) {
    return cons(args->first, (Cell*)(args->rest->first));
}
void* primeAtom(Environment* env, Cell* args) {
    if(args->first == 0 || isAtom(args->first)) { //
        return atomTrue;
    }
    return 0;
}
void* primeEq(Environment* env, Cell* args) {
    void* fst = args->first;
    void* snd = args->rest->first;
    if(fst == 0 && snd == 0 ||
            isAtom(fst) && isAtom(snd) && fst == snd) {
        return atomTrue;
    }
    return 0;
}
void* primeList(Environment* env, Cell* args) {
    return args;
}
// 函数和名称对应的表,用于注册函数
PrimeFunc exprArgFuncTable[] = {
    primeQuote,
    primeLambda,
    primeLabel,
    primeCond,
    primeDefun
};
const char* exprArgFuncNames[] = {
    "quote",
    "lambda",
    "label",
    "cond",
    "defun"
};
PrimeFunc valArgFuncTable[] = {
    primePrint,
    primeFirst,
    primeRest,
    primeCons,
    primeAtom,
    primeEq,
    primeList
};
const char* valArgFuncNames[] = {
    "print",
    "car",
    "cdr",
    "cons",
    "atom",
    "eq",
    "list"
};
// 注册函数到lisp
#define REGISTER_FUNCTIONS(env, type) registerFunctions(env, type##Names, type##Table, sizeof(type##Names)/sizeof(const char*))
void registerFunctions(Environment& env, const char** names, PrimeFunc* funcs, size_t n) {
    for (unsigned i=0; i<n; i++) {
        Atom nameAtom = createAtom(names[i]);
        env[nameAtom] = funcs + i;
    }
}
bool isExprArgFunc(void* p) {
    const char* tab = (const char*)exprArgFuncTable;
    return tab <= p && p < tab + sizeof(exprArgFuncTable);
}
bool isValArgFunc(void* p) {
    const char* tab = (const char*)valArgFuncTable;
    return tab <= p && p < tab + sizeof(valArgFuncTable);
}
void* getValue(Environment* env, Atom name) {
    Environment::iterator it = env->find(name);
    if(it != env->end())
        return it->second;
    return 0;
}
void* evalValue(Environment* env, void* v) {
    if(isAtom(v)) {
        return getValue(env, Atom(v));
    } else {
        return evalExpression(env, (Cell*)v);
    }
}
Cell* evalArguments(Environment* env, Cell* args) {
    if(args == 0)
        return 0;
    return cons(evalValue(env, args->first), evalArguments(env, args->rest));
}
// 对一个表达式(也是一个表)求值
void* evalExpression(Environment* env, Cell* expr) {
    if(expr == 0) // 空表
        return 0;
    void* v  = evalValue(env, expr->first); // 对表的第一个元素求值
    if(v != 0) {
        if(isExprArgFunc(v)) { // 如果是传表达式的函数
            PrimeFunc fn = *(PrimeFunc*)v; // 转换成函数指针
            return fn(env, expr->rest);    // 将表达式直接传递给函数
        } else if(isValArgFunc(v)) {  // 如果是传值的函数
            PrimeFunc fn = *(PrimeFunc*)v;
            return fn(env,
                evalArguments(env, expr->rest)); // 对参数的表达式求值,再传递给函数
        } else {
            if(isCell(v)) { // 如果是Cell
                Cell* c = (Cell*)v;
                Atom fst = Atom(c->first);
                if(Atom(c->first) == atomLambda) { // 如果是lambda表达式
                    Cell* rest = c->rest;
                    Cell* params = (Cell*)(rest->first);
                    void* body = rest->rest->first;
                    Environment e = *env;
                    Cell* argus = evalArguments(env, expr->rest); // 对参数求值
                    while (params) { // 将参数的值绑定到形参上
                        Atom name = Atom(params->first);
                        e[name] = argus->first;
                        params = params->rest;
                        if(argus)
                            argus  = argus->rest;
                    }
                    return evalValue(&e, body); // 对lambda表达式体求值
                }
            }
        }

    }
    return 0;
}

void evalStatement( Environment& env, Cell* stmt ) {
    evalExpression(&env, stmt);
    gc(env);
}
// ------ GC -------
// 简单的垃圾回收

void* gcmem;
char* gcptr;
void* tomem;
char* toptr;
const int MAX_MEM = 64*1024;
bool isCell(void* p) {
    return gcmem <= p && p < gcptr;
}
void gcInit() {
    gcptr = (char*)(gcmem = malloc(MAX_MEM));
}
void gcEnd() {
    free(gcmem);
}
// 4字节对齐
inline void* align(char* val) {
    return (void*)(((unsigned)val + 3) & ~3);
}
// gcmem指向大块内存,每次分配直接从中划出来
void* gcAlloc(size_t size) {
    assert(gcptr < (char*)gcmem + MAX_MEM);
    void* p = 0;
    if(gcptr + size < (char*)gcmem + MAX_MEM) {
        p = gcptr;
        gcptr = (char*)align(gcptr + size);
    }
    return p;
}
// 回收

// 遍历内存进行复制
void* gcVisit(Cell* c) {
    void* p = c->first;
    if(tomem <= p && p < toptr) {
        return p;
    }
    Cell* toc = (Cell*)toptr; // 将访问到Cell复制到新分配的内存中
    *toc = *c;
    c->first = toptr;
    toptr += sizeof(Cell);
    if(isCell(toc->first)) { // 如果第一个元素是一个Cell
        toc->first = gcVisit((Cell*)(toc->first)); // 访问之
    }
    if(toc->rest) {
        toc->rest = (Cell*)gcVisit(toc->rest); // 访问其它的元素
    }
    return toc;
}

// 在执行完一个语句后,进行一次回收
void gc(Environment& env) {
    toptr = (char*)(tomem = malloc(MAX_MEM)); // 先分配同样大的内存
    for(Environment::iterator it=env.begin(); it != env.end(); ++it) { // 从环境中变量使用的Cell出发
        if(isCell(it->second)) {
            it->second = gcVisit((Cell*)(it->second)); // 访问每个用到的Cell
        }
    }
    free(gcmem);
    gcmem = tomem;
    gcptr = toptr;
}
// 判断括号是否匹配
bool parenMatched(const string& stmt) {
    int counter = 0;
    for(unsigned i=0; i<stmt.length(); i++) {
        if(stmt[i] == '(')
            ++ counter;
        else if(stmt[i] == ')')
            -- counter;
        if(counter < 0)
            return false;
    }
    return counter == 0;
}

void run(Environment& env, char* filename) {
    ifstream istrm(filename);

    if(!istrm.is_open()) {
        cerr << "open file fail!" << endl;
        return;
    }
    string statement = "";
    while (!istrm.eof()) {
        char line[512];
        istrm.getline(line, 512);
        char* comStart = strchr(line, ';');
        if(comStart) { // 如果是注释,跳过
            *comStart = '\0';
        }
        if(statement == "") {
            statement = line;
        } else {
            statement += string(" ")+line;
        }
        if(!parenMatched(statement)) { // 如果括号不匹配,说明这一行还没有结束
            continue;
        }
        Result r = parse(statement.c_str());
        if(r.parsed == 0)
            continue;
        evalStatement(env, (Cell*)r.parsed);
        statement = "";
    }
}
int main(int argc, char** argv) {
    atomTable = new string[MAX_ATOMS];
    lastAtom = atomTable;
    gcInit();

    Environment env;
    atomTrue   = createAtom("t");
    atomLambda = createAtom("lambda");
    atomQuote  = createAtom("quote");

    REGISTER_FUNCTIONS(env, exprArgFunc);
    REGISTER_FUNCTIONS(env, valArgFunc);

    env[createAtom("p")] = env[createAtom("print")];
    char* filename = "test.lsp";
    if(argc > 1) {
        filename = argv[1];
    }
    run(env, filename);
    gcEnd();
    delete[] atomTable;
    return 0;
}

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
第5期 | EasyFlash,让 Flash 成为小型 KV 数据库
JNI介绍
Ril分析一
从Android init.rc到SystemServer.java
JNI官方规范中文版——如何在JNI中抛出Java异常
android jni 学习笔记
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服