summaryrefslogtreecommitdiff
path: root/godel/grammar.peg
blob: a66d5a59c2aee992556624d52fb0a6a17bc2cb0c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
Program = lines: (ProgramInstruction / (_/[\n]))* {
  return { instructions: lines.filter((line) => typeof line !== "string" || line.trim() != "") };
}

ProgramInstruction = _? instruction: (LabeledInstruction / Instruction) _? [\n]? {
  let x = 0;
  let y = 0;
  if (instruction.label) {
    x = instruction.label.godel;
    y = instruction.instruction.godel;
  } else {
    y = instruction.godel;
  }
  return { instruction, godel: ((2 ** x) * ((2 * y) + 1) - 1) };
}

LabeledInstruction = label:Label _ instruction:Instruction {
  return { label, instruction };
}

Label = "[" _? label:LABEL_V _? "]" {
  return label;
}
  
Instruction = conditional: Conditional { return { conditional, godel: conditional.godel }; } 
  / assignment: Assignment { return { assignment, godel: assignment.godel }; }
  / goto: Goto { return { goto, godel: goto.godel }; }

Goto = GOTO _ label: LABEL_V {
  return { label, godel: label.godel + 2 };
}

Conditional = "IF" _ variable: VAR  _? "!=" _? "0" _ goto: Goto {
  const y = variable.godel - 1;
  const x = goto.godel;
  return { variable, goto, godel: ((2 ** x) * ((2 * y) + 1) - 1) };
}

Assignment = variable: VAR _ "<-" _ expr: Expression {
  if (expr.left.symbol != variable.symbol) {
    error("left hand variable must match right hand");
  }
  const x = expr.instructionNumber;
  const y = variable.godel - 1;
  return { variable, expr, godel: ((2 ** x) * ((2 * y) + 1) - 1) };
}

Expression = left: VAR _ opr: OPERATION _ "1" {
  const instructionNumber = { "+" : 1, "-" : 2 }[opr];
  return { left, opr, instructionNumber };
} / left: VAR  {
  return { left, instructionNumber: 0 };
}

VAR = symbol:"Y" { return { symbol, godel: 1 }; } / symbol:("X" / "Z") ind:Integer+ {
  const index = parseInt(ind);
  const order = ["X", "Z"];
  const godel = index * order.length + order.indexOf(symbol);
  return { symbol: symbol + ind, godel };
}

GOTO = "GOTO"

OPERATION = "+" / "-"

LABEL_V = symbol:END_LABEL { return symbol } / symbol:[A-E] ind:Integer+ {
  const index = parseInt(ind);
  const godel = (symbol.charCodeAt(0) - "A".charCodeAt(0) + 1) + 5*(index-1);
  return { symbol: symbol + ind, godel };
}

END_LABEL = "E1"

Integer "integer"
  = [0-9]+ { return parseInt(text(), 10); }

_ "whitespace" = [ \t]+ {  }