純粋な PEG はインデントを解析できません。
しかし、peg.jsはできます。
私は簡単な実験を行い (不正行為に関する Ira Baxter のコメントに触発されて)、単純なトークナイザーを作成しました。
より完全なソリューション (完全なパーサー) については、次の質問を参照してください: PEG.js でインデント レベルを解析する
/* Initializations */
{
function start(first, tail) {
var done = [first[1]];
for (var i = 0; i < tail.length; i++) {
done = done.concat(tail[i][1][0])
done.push(tail[i][1][1]);
}
return done;
}
var depths = [0];
function indent(s) {
var depth = s.length;
if (depth == depths[0]) return [];
if (depth > depths[0]) {
depths.unshift(depth);
return ["INDENT"];
}
var dents = [];
while (depth < depths[0]) {
depths.shift();
dents.push("DEDENT");
}
if (depth != depths[0]) dents.push("BADDENT");
return dents;
}
}
/* The real grammar */
start = first:line tail:(newline line)* newline? { return start(first, tail) }
line = depth:indent s:text { return [depth, s] }
indent = s:" "* { return indent(s) }
text = c:[^\n]* { return c.join("") }
newline = "\n" {}
depths
くぼみの積み重ねです。indent() はインデント トークンの配列を返し、start() は配列をアンラップしてパーサーをストリームのように動作させます。
peg.jsはテキストに対して次を生成します。
alpha
beta
gamma
delta
epsilon
zeta
eta
theta
iota
これらの結果:
[
"alpha",
"INDENT",
"beta",
"gamma",
"INDENT",
"delta",
"DEDENT",
"DEDENT",
"epsilon",
"INDENT",
"zeta",
"DEDENT",
"BADDENT",
"eta",
"theta",
"INDENT",
"iota",
"DEDENT",
"",
""
]
このトークナイザーは、不適切なインデントもキャッチします。