【自制程式語言】1 - 基本語句(1)

計算機知識雜談發表於2021-12-31

前言

已經是年底了,本篇文章應該也是今年的最後一篇了。於是,突發奇想,想要來自制一個程式語言。也算是鍛鍊自己的程式碼能力吧。

冰凍三尺,非一日之寒。

同樣,製作任何的東西,都是這樣,羅馬不是一天建成的,一個好的程式語言也不是一天建成的。我們能做的,就是先從基礎開始,一點一點往上加入內容。一開始的東西可能非常簡陋,甚至不能叫做是程式語言。但最終,隨著新功能的加入,我們會發現,做出來的東西越來越像樣了。

在閱讀文章的時候,建議大家也動手寫寫。不需要完全一樣,想要加入一些新的東西或者其他的修改也可以,儘可以根據自己的喜好修改。

實現功能

本期的功能實現,非常簡單。
首先是編譯方式的處理。我們使用樸素的命令列引數的形式,我們的編譯的程式名(編譯器的名字)是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);
                }
        }
}

相關文章