[プログラミング言語の作り方] 複数文(セミコロン)対応の作り方

複数文はセミコロンで区切るとする。
### source.3

print("hello world1");
print("hello world2");
print("hello world3");

### lexer.js
正規表現にセミコロンを追加

module.exports = function(source){
    var tokens = source.split(/(".*"|print|;)|\n/);

    tokens = tokens.filter(a=>a);

    return tokens;
}

### parser.js

module.exports = parser;
var {expect, accept, show, error} = require("./utils.js");

var tokens;

function parser(t){
    tokens = t;
    return semi();
}

function semi(){
    var left = callprint();

    var op;
    while(op = accept(tokens, ";")){
        var right = callprint();
        left = {left, op, right};
    }
    return left;
}

function callprint(){
    if(tokens.length==0) return;

    var left = expect(tokens, "print");

    var op = expect(tokens, "(");

    var msg = tokens.shift();
    num = calc(msg.length);

    var right = msg.substr(1, num);

    op += expect(tokens,")");

    return {left, op, right};
}

function calc(len) {
    var total = len - 2;
    return Number.isInteger(total) > 0 ? total : 0;
}

上記を実行すると、leftが入れ子になる
[[print, (), hell1] [;] [print, (), hell1]] [;] [print, (), hell1]

### run.js

const { error } = require("./utils");

module.exports = run;

function run(a){
    if(!a) return;
    if(!a.op){
        if(a[0] == '"') return a.substr(1, a.length-2);
        return a;
    } else if (a.op==";"){
        run(a.left);
        run(a.right);
    } else if(a.op == "()") {
        var func = run(a.left);
        if(func == "print"){
            var msg = run(a.right)
            console.log(msg);
        } else {
            error("未実装の関数呼び出し func=", func);
        } 
    } else {
        error("未実装の演算子 op=", a.op)
    }
} 

run(a.left); run(a.right); と左から実行することで、上から入れ子になっている式を上から順番に実行する。

$ node interpretor.js
token =[
‘print’, ‘(‘,
‘”hello world1″‘, ‘)’,
‘;’, ‘print’,
‘(‘, ‘”hello world2″‘,
‘)’, ‘;’,
‘print’, ‘(‘,
‘”hello world3″‘, ‘)’,
‘;’
]
ast={
left: {
left: {
left: { left: ‘print’, op: ‘()’, right: ‘hello world1’ },
op: ‘;’,
right: { left: ‘print’, op: ‘()’, right: ‘hello world2’ }
},
op: ‘;’,
right: { left: ‘print’, op: ‘()’, right: ‘hello world3’ }
},
op: ‘;’,
right: undefined
}
hello world1
hello world2
hello world3

parserでセミコロンが来たら、セミコロンをopにしてleftとrightに入れるというのは面白い
C, C++はセミコロンがあるが、pythonは文末にセミコロンがないけどどうやってるんだろうか?