前言
已經是年底了,本篇文章應該也是今年的最後一篇了。於是,突發奇想,想要來自制一個程式語言。也算是鍛鍊自己的程式碼能力吧。
冰凍三尺,非一日之寒。
同樣,製作任何的東西,都是這樣,羅馬不是一天建成的,一個好的程式語言也不是一天建成的。我們能做的,就是先從基礎開始,一點一點往上加入內容。一開始的東西可能非常簡陋,甚至不能叫做是程式語言。但最終,隨著新功能的加入,我們會發現,做出來的東西越來越像樣了。
在閱讀文章的時候,建議大家也動手寫寫。不需要完全一樣,想要加入一些新的東西或者其他的修改也可以,儘可以根據自己的喜好修改。
實現功能
本期的功能實現,非常簡單。
首先是編譯方式的處理。我們使用樸素的命令列引數的形式,我們的編譯的程式名(編譯器的名字)是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);
}
}
}