【自制编程语言】1 - 基本语句(1)
前言
已经是年底了,本篇文章应该也是今年的最后一篇了。于是,突发奇想,想要来自制一个编程语言。也算是锻炼自己的代码能力吧。
冰冻三尺,非一日之寒。
同样,制作任何的东西,都是这样,罗马不是一天建成的,一个好的编程语言也不是一天建成的。我们能做的,就是先从基础开始,一点一点往上加入内容。一开始的东西可能非常简陋,甚至不能叫做是编程语言。但最终,随着新功能的加入,我们会发现,做出来的东西越来越像样了。
在阅读文章的时候,建议大家也动手写写。不需要完全一样,想要加入一些新的东西或者其他的修改也可以,尽可以根据自己的喜好修改。
实现功能
本期的功能实现,非常简单。
首先是编译方式的处理。我们使用朴素的命令行参数的形式,我们的编译的程序名(编译器的名字)是main,那么编译方式如下:
main test.txt
表示运行test.txt。
指令的处理,我们目前先写两个指令,练练手。分别是:SET和PRINT
SET
SET A 10
表示定义一个变量,值为10.
PRINT
输出变量的值。
命令行参数
现在我们是需要通过命令行的参数来获取要编译的文件名的。获取的方法,可以使用命令行参数的形式,这是C++语言的自带功能(不需要依赖操作系统的库)。
int main(int argc,char** argv);
通过这样的定义,我们就能获取命令行参数了。
我们做个试验,看看这些命令行参数是如何在argc和argv中排放的。
#include<iostream>
using namespace std;
int main(int argc,char** argv){
for(int i=0;i<argc;i++){
cout<<i<<" "<<argv[i]<<endl;
}
}
运行时,随意输入一些参数进去。
因此,我们发现:从argv[1]开始往后,都是命令行参数,顺次存放在argv[1],argv[2]...中。
语法实现
关于变量的值的存放,我们考虑使用结构体。
其中,VARI_CTL控制多个变量的存放。(其实这里的vari数组应该使用malloc分配动态数组,否则变量最多只能有255个,这里偷了个懒)然后封装类函数,查询变量的值。
从文件读入,可以使用fscanf。我们这里使用循环的方式反复读入语句,由于每个语句使用空格分割,使用fscanf读入字符串即可。
(如果PRINT语句的语法修改为PRINT(A)
的话,实现方法会更加复杂,因为要判断括号)
代码添加了注释,读起来应该比较容易理解。
完整的代码:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
struct VARIABLE{
string name; //变量名
int val; //变量的值
};
struct VARI_CTL{
VARIABLE vari[255]; //255个变量
int count; //变量目前为止的个数
VARI_CTL(){
count=0;
}
void set(string name,int a){ //设置一个变量
vari[count].name=name;
vari[count].val=a;
count++;
}
VARIABLE &get_vari(string name){
for(int i=0;i<count;i++){
if(vari[i].name==name)return vari[i];
}
cout<<"[Error]:Can\'t find variable name.";
exit(0);
}
int get_val(string name){
for(int i=0;i<count;i++){
if(vari[i].name==name)return vari[i].val;
}
cout<<"[Error]:Can\'t find variable name.";
exit(0);
}
}vari_ctl;
int main(int argc,char** argv){
string s; //每次从文件读入的字串
char sc[100]; //为了使用fscanf,需要使用C风格字符串
FILE *fp=fopen(argv[1],"r");
if(fp==NULL){ //找不到文件
printf("[Error]:Can\'t find input file \"%s\" .",argv[1]);
exit(0);
}
for(;;){
fscanf(fp,"%s",sc);
s=sc; //使用string类型更加方便使用
if(s=="EXIT"){
system("pause");
exit(0);
}
else if(s=="SET"){
char t[100],u[100]; //格式:SET 变量名 数字
fscanf(fp,"%s %s",t,u);
int a;
sscanf(u,"%d",&a); //字符串转数字
vari_ctl.set(t,a); //设置数值
}
else if(s=="PRINT"){
char t[100];
fscanf(fp,"%s",t);
if(t[0]=='\"'){ //字符串的输出
for(int i=1;i<strlen(t)-1;i++){
printf("%c",t[i]);
}
}
else{
cout<<vari_ctl.get_val(t);
}
}
else{
cout<<"[Error]:Illegal command.";
exit(0);
}
}
}