MyHLは、haribote HL-8cを改造したバージョンです。
デクリメント演算子を追加
@@ -138,6 +138,7 @@ int tc[10000]; // トークンコード列を格納する enum { PlusPlus, + MinusMinus, Equal, NotEq, Les, @@ -207,6 +208,7 @@ enum { String defaultTokens[] = { "++", + "--", "==", "!=", "<", @@ -281,6 +283,7 @@ void initTc(String *defaultTokens, int len) typedef enum { Prefix_PlusPlus = 2, + Prefix_MinusMinus = 2, Prefix_Minus = 2, Prefix_Ex = 2, Infix_Multi = 4, @@ -303,6 +306,7 @@ typedef enum { Precedence precedenceTable[][2] = { [PlusPlus] = {NoPrecedence, Prefix_PlusPlus}, + [MinusMinus] = {NoPrecedence, Prefix_MinusMinus}, [Equal] = {Infix_Equal, NoPrecedence}, [NotEq] = {Infix_NotEq, NoPrecedence}, [LesEq] = {Infix_LesEq, NoPrecedence}, @@ -414,6 +418,7 @@ typedef enum { OpBand, OpShr, OpAdd1, + OpSub1, OpNot, OpNeg, OpGoto, @@ -497,17 +502,19 @@ int evalExpression(Precedence precedence) if (match(99, "( !!**0 )", epc)) { // 括弧 res = expression(0); } - else if (match(72, "!!*0!!*1[!!**2]", epc) && tc[wpc[0]] == PlusPlus) { // 前置インクリメント + else if (match(72, "!!*0!!*1[!!**2]", epc) && (tc[wpc[0]] == PlusPlus || tc[wpc[0]] == MinusMinus)) { // 前置インクリメント・デクリメント + int oper = tc[wpc[0]]; e2 = expression(2); res = tmpAlloc(); putIc(OpAryGet, &vars[tc[wpc[1]]], &vars[e2], &vars[res], 0); - putIc(OpAdd1, &vars[res], 0, 0, 0); + putIc(OpAdd1 + oper - PlusPlus, &vars[res], 0, 0, 0); putIc(OpArySet, &vars[tc[wpc[1]]], &vars[e2], &vars[res], 0); } - else if (tc[epc] == PlusPlus) { // 前置インクリメント + else if (tc[epc] == PlusPlus || tc[epc] == MinusMinus) { // 前置インクリメント・デクリメント + int oper = tc[epc]; ++epc; - res = evalExpression(getPrecedence(Prefix, PlusPlus)); - putIc(OpAdd1, &vars[res], 0, 0, 0); + res = evalExpression(getPrecedence(Prefix, oper)); + putIc(OpAdd1 + oper - PlusPlus, &vars[res], 0, 0, 0); } else if (tc[epc] == Minus) { // 単項マイナス ++epc; @@ -538,21 +545,23 @@ int evalExpression(Precedence precedence) Precedence encountered; // ぶつかった演算子の優先順位を格納する e0 = 0, e1 = 0, e2 = 0; - if (tc[epc] == PlusPlus) { // 後置インクリメント + if (tc[epc] == PlusPlus || tc[epc] == MinusMinus) { // 後置インクリメント・デクリメント + int oper = tc[epc]; ++epc; e0 = res; res = tmpAlloc(); putIc(OpCpy, &vars[res], &vars[e0], 0, 0); - putIc(OpAdd1, &vars[e0], 0, 0, 0); + putIc(OpAdd1 + oper - PlusPlus, &vars[e0], 0, 0, 0); } - else if (match(73, "[!!**0]!!*1", epc) && tc[wpc[1]] == PlusPlus) { // 後置インクリメント + else if (match(73, "[!!**0]!!*1", epc) && (tc[wpc[1]] == PlusPlus || tc[wpc[1]] == MinusMinus)) { // 後置インクリメント・デクリメント + int oper = tc[wpc[1]]; e1 = res; res = tmpAlloc(); e0 = expression(0); epc = nextPc; putIc(OpAryGet, &vars[e1], &vars[e0], &vars[res], 0); e2 = tmpAlloc(); - putIc(OpAdd, &vars[e2], &vars[res], &vars[One], 0); + putIc(OpAdd + oper - PlusPlus, &vars[e2], &vars[res], &vars[One], 0); putIc(OpArySet, &vars[e1], &vars[e0], &vars[e2], 0); } else if (match(70, "[!!**0]=", epc)) { @@ -962,6 +971,7 @@ void exec() case OpNeg: *icp[1] = -*icp[2]; icp += 5; continue; case OpNot: *icp[1] = !*icp[2]; icp += 5; continue; case OpAdd1: ++(*icp[1]); icp += 5; continue; + case OpSub1: --(*icp[1]); icp += 5; continue; case OpMul: *icp[1] = *icp[2] * *icp[3]; icp += 5; continue; case OpDiv: *icp[1] = *icp[2] / *icp[3]; icp += 5; continue; case OpMod: *icp[1] = *icp[2] % *icp[3]; icp += 5; continue;
参考
「10日くらいでできる!プログラミング言語自作入門」
インタプリタをC言語で実装しながらプログラミング言語自作に入門するテキストです。無料で読めます。続編ではインタプリタをJITコンパイラに改造します。
「10日くらいでできる!プログラミング言語自作入門」の続編#1-1
プログラミング言語自作入門で実装したインタプリタを、x86用またはx64用のJITコンパイラに改造します。後半では、レジスタ変数の導入や無駄なメモリアクセスの削減、コンパイル時の定数計算などの最適化に取り組みます。
「10日くらいでできる!プログラミング言語自作入門」の「残された課題」に関する補足
作者の川合秀実さんが、a21_txt01_10の「残された課題」に取り組む順序について、再検討した内容を共有してくれました。残された課題は、記号表やスタックを自前で実装する必要があるため、はりぼて言語の公式処理系の構造をベースに言語開発をしたい人にとって良い課題となるでしょう。