MyLisp项目日志:项目介绍和读取输入实现

895 words

项目介绍

这是一个超轻量级的C/C++项目,使用C/C++模拟实现一个简单的Lisp(一种函数式程序设计语言),会使用一些外部的库进行初始化工作,例如mpc、editline等

我们会使用类Python的REPL模式,使用Lisp程序,并不直接提供系统的编译运行环境,整个代码量大概在1000行左右

主要难点

  1. 语法规则与解析用户输入
  2. 递归与错误处理
  3. S表达式,Q表达式
  4. 函数,标准库

我将会在这里逐步实现这个小项目并记录实现过程中出现的问题以及解决方案

会先使用C语言实现,再考虑使用C++补充和优化

读取输入的实现

基本思路

首先这是一个类Python的命令行输入的模式,基本思路就是使用一个while(1)循环,然后不断读入,再进行解析处理

如下

1
2
3
4
5
while(1)
{
char* input = readline("MyLisp> ");
printf("The sentence is %s\n", input);
}

这里的readline是为了适配linux和mac,我们重新写的一个有相似功能的函数,他会输出MyLisp>提示符,然后返回input,也就是输入的语句,通过这个调用我们可以猜测在readline内部是malloc出一段空间的

跨平台问题

对于不同平台,我们可以使用条件编译处理

如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ifdef _WIN32

char* readline(char* prompt){}
void add_history(char* unused){}


#else
#ifdef __linux__ // 在linux平台下
#include<editline/readline.h>
#include<editline.history.h>
#endif

#ifdef __MACH__ // 在mac平台下
#include<editline/readline.h>
#endif
#endif

这样就能实现跨平台了

如何读取输入

在linux和mac中都有现成的函数可以调用,在windows下还是需要手动实现readline函数的,add_history函数就直接空实现即可

对于读入,我们一般都会设置Buffer缓冲区,然后等到读入的时候,先读入到缓冲区中,再拷贝到malloc的内存中,最后返回

如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 为实现跨平台功能
// 在windows平台下定义实现editline和history的同名函数

#define INPUT_MAX 2048 // 缓冲区最大值

#include<string.h>
static char Buffer[INPUT_MAX]; // Buffer输入缓冲区


char* readline(char* prompt) // 模拟实现readline
{
fputs(prompt, stdout);
fgets(Buffer, INPUT_MAX, stdin);


char* tmp = malloc(strlen(Buffer) + 1);
if (tmp != NULL)
{
strcpy(tmp, Buffer);
tmp[strlen(tmp) - 1] = '\0';
}

return tmp;
}

void add_history(char* unused)
{}

打印提示信息

这里就是输出作者信息,版本号之类的了

1
2
3
4
5
6
7
8
9
10
11
#include"Pt.h"

void PrintPrompt()
{
printf("MyLisp Version 0.0.1\n");
printf("Added basic interactive prompts and read user input functionality\n");
printf("By jasmine-leaf");
printf("Press Ctrl+c to Exit\n\n\n");
}
// v0.0.1
// 添加了基础的交互提示,读取用户输入功能

warning LNK4042: 对象被多次指定;已忽略多余的指定

这里遇到一个链接错误,可能是因为笔者在创建文件时后缀名没有写对导致的

会出现两个警告

  • warning LNK4042: 对象被多次指定;已忽略多余的指定

  • error LNK2001: 无法解析的外部符号

最主要原因是,工程的不同路径下存在相同名称的文件或者是在属性窗口修改了文件的设定

解决方案

方法一:项目右键 -> 属性 -> C/C++ -> 输出文件 -> 对象文件名,将原来的$(IntDir)改为$(IntDir)/%(RelativeDir)/

方法二:将LNK4042的.h和.cpp从项目中排除,然后再通过添加现有项方式将排除的.h和.cpp重新添加进来(注意一定要先排除再进行添加操作,否则问题仍然解决不了)

Comments