構文木をいじれるC言語風データ定義言語
2chにサンプルだけ書いたら変人扱いされたのですが、とにかくC言語風のデータ定義言語を考えています。仮にCEX(C like EXpression)と名づけました。
基本的な考え方
CEXのデータの基本形は
トークン[](){}
です。
各カッコ内は、";"でトークンを分割し、さらに","で分割します。その分割された中に入るデータはCEXが再帰的に入ることになります。
パーサーは、字句解析部でほぼ、D言語の字句解析に近いことを行い、そのトークンをCEXの考え方に基づいて構文木を作成します。
トークン、[]、()、{}は全て省略可能です。
例)
void main(){ printf("hello world\n"); }
は、
void(){} main(){ printf[]("hello world\n"){}; }
の省略形と言った感じです。実際には括弧は存在する、存在しないのフラグを持つか、nullと長さ0のリストで判定することになると思います。
このデータを操作するオブジェクトの例を以下に示します。
public class CEX { private char _k; private CEX _a; private CEX _p; private CEX _b; public char k() {return _k;} public void k(char str) {_k = k;} public CEX a() {return _a;} public CEX a(int semi) {return _a[semi];} public CEX a(int semi, int white){return _a[semi][white];} public CEX a(int semi, int white, int canma) {return _a[semi][white][canma];} public CEX a0(){return _a[0][0][0];} public CEX as(int semi){return _a[semi][0][0];} public CEX aw(int white){return _a[0][white][0];} public CEX ac(int canma){return _a[0][0][canma];} public CEX asw(int semi,int white){return _a[semi][white][0];} public CEX asc(int semi,int canma){return _a[semi][0][canma];} public CEX awc(int white,int canma){return _a[0][white][canma];} public char astr() {return "[" ~ str(_a) ~ "]";} public CEX p() {return _p;} public CEX p(int semi) {return _p[semi];} public CEX p(int semi, int white){return _p[semi][white];} public CEX p(int semi, int white, int canma) {return _p[semi][white][canma];} public CEX p0(){return _p[0][0][0];} public CEX ps(int semi){return _p[semi][0][0];} public CEX pw(int white){return _p[0][white][0];} public CEX pc(int canma){return _p[0][0][canma];} public CEX psw(int semi,int white){return _p[semi][white][0];} public CEX psc(int semi,int canma){return _p[semi][0][canma];} public CEX pwc(int white,int canma){return _p[0][white][canma];} public char pstr() {return "[" ~ str(_p) ~ "]";} public CEX b() {return _b;} public CEX b(int semi) {return _b[semi];} public CEX b(int semi, int white){return _b[semi][white];} public CEX b(int semi, int white, int canma) {return _b[semi][white][canma];} public CEX b0(){return _b[0][0][0];} public CEX bs(int semi){return _b[semi][0][0];} public CEX bw(int white){return _b[0][white][0];} public CEX bc(int canma){return _b[0][0][canma];} public CEX bsw(int semi,int white){return _b[semi][white][0];} public CEX bsc(int semi,int canma){return _b[semi][0][canma];} public CEX bwc(int white,int canma){return _b[0][white][canma];} public char bstr() {return "[" ~ str(_b) ~ "]";} public char toString() { k ~ " " ~ astr() ~ pstr() ~ bstr(); } private static char str(CEX s){ char str; for (int i = 0; i < s.length; i++) { for (int j = 0; j < s[i].length; j++) { for (int k = 0; k < s[i][j].length; k++) { str ~= s[i][j][k].toString() ~ " "; } str[str.length] = ","; } str[str.length] = ";"; } return str[0 .. str.length - 1]; } } public class CEXReader { static public CEX read(char str) { Token tokens = CEXTokenizer.tokens(str); CEX cex = new CEX(); return cex; } } public class CEXWriter { static public char write(CEX cex) { char[] str; return str; } }
長くなるので
a:[]
p:()
b:{}
s:';'
c:','
w:' '
と略しています。
この言語でプログラミング言語(仮にCXP C like eXpression Programing language)を作るとした場合のサンプルコードをいかに示します。
class[public;a;;] { }; abstractClass[public;absc1;;] { }; interface[public;b;;] { }; /** * publicでaクラスを継承し、bインターフェイスを持つnameという名前をもつクラス */ class[public;name;a;b] { function[public; ret; name](var(int){a},var(int){b}) { }; function[public,static; ret; name](var[inout](int){a}, var[out](int){b})) { }; }; struct[public;S1] { var[;int] a; var[;int] b; var[;int] c; }; function[public; void; main]() { var[static](int) {a=12,b,c}; a = 1 + 2 * 14; // (((a = 1)+2)*14)と解釈される。演算子による優先順位付けはなし。 a = (1 + (2 * 14)); // とかかなくてはならない。 let(a = 1 + 2 * 14);// a=(1+(2*14))と構文解析してくれる拡張構文。 var[static](int[12]){d=(1,2,3,4,5,6,7,8,9,10,11,12)}; var[static](S1){s={a=10,b=10,c=10}}; var[static](int[char[ ] ]){d=["a"=1,"b"=2,"c"=3]}; var(name){c1=name.new()};// new演算子はなくて、newメソッドを使う。 c1.delete();// デリート if(a==b){ }else{ }; // ローカルブロックはエラー ラベルを使うこと。 var(function[public;void;]()){a=main};// 関数ポインタ for[c](var(int){i=0};i<10;i++) {//[c]はラベル break; continue; switch(a){ case[1]{ break[c];// forからbreak } case[2]{ continue[c];// forをcontinue } case[3]{ // 3,4を実行する。 } case[4]{ break; } // case[5]a++; エラー }; }; return[](){}; };
と言った感じになると思います。
このプログラム言語は構文ツリーそのものですので、構文を追加するようなことが比較的簡単であるはずで、そういう構文追加機能を考えていますが、LISPなどのプログラミング経験が少ないので、勉強中です。