1 // Toy interpreter parser. 2 // 3 // Copyright (C) 2014-2015 Iain Buclaw. 4 // This program is free software; you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation; either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 14 // You should have received a copy of the GNU General Public License 15 // along with this program. If not, see <http://www.gnu.org/licenses/>. 16 17 // Written by Iain Buclaw <ibuclaw@gdcproject.org> 18 19 module toy.parse; 20 21 import toy.ast; 22 import toy.combinator; 23 import toy.lex; 24 import toy.diag; 25 26 ///// Parser ///// 27 28 Statement parse(Token[] tokens) 29 { 30 Parser ast = new Phrase(stmtList()); 31 Result result = ast(tokens, 0); 32 33 if (result.values.length != 1 || (cast(Statement) result.values[0]) is null) 34 throw new ParseError("error occurred at " ~ tokens[result.pos].value); 35 36 return cast(Statement) result.values[0]; 37 } 38 39 /// Statements 40 41 Parser stmtList() 42 { 43 return (stmtTerm() * new Reserved(";")) 44 & (Statement l, Keyword sep, Statement r) => new CompoundStatement(l, r); 45 } 46 47 Parser stmtTerm() 48 { 49 return stmtAssign() | stmtIf() | stmtWhile() | stmtPrint(); 50 } 51 52 Parser stmtAssign() 53 { 54 return (valueIdent() + new Reserved(":=") + arithExp()) 55 ^ (Expression name, Keyword eq, Expression value) => new AssignStatement(name, value); 56 } 57 58 Parser stmtIf() 59 { 60 return (new Reserved("if") + boolExp() 61 + new Reserved("then") + new Lazy(&stmtList) 62 + new Optional((new Reserved("else") + new Lazy(&stmtList)) 63 ^ (Keyword e, Statement elsebody) => elsebody) 64 + new Reserved("end")) 65 ^ (Keyword i, Expression condition, Keyword t, Statement ifbody, Statement elsebody, Keyword e) 66 => new IfStatement(condition, ifbody, elsebody); 67 } 68 69 Parser stmtWhile() 70 { 71 return (new Reserved("while") + boolExp() 72 + new Reserved("do") + new Lazy(&stmtList) 73 + new Reserved("end")) 74 ^ (Keyword w, Expression condition, Keyword d, Statement whilebody, Keyword e) 75 => new WhileStatement(condition, whilebody); 76 } 77 78 Parser stmtPrint() 79 { 80 return (new Reserved("print") + (boolExp() | arithExp())) 81 ^ (Keyword w, Expression e) => new PrintStatement(e); 82 } 83 84 /// Boolean Expressions 85 86 Parser boolExp() 87 { 88 return (boolTerm() * (new Reserved("and") | new Reserved("or"))) 89 & (Expression l, Keyword op, Expression r) => (op.value == "and") ? new AndExp(l, r) : new OrExp(l, r); 90 } 91 92 Parser boolTerm() 93 { 94 return boolNot() | boolCmp() | boolGroup(); 95 } 96 97 Parser boolNot() 98 { 99 return (new Reserved("not") + new Lazy(&boolTerm)) 100 ^ (Keyword op, Expression e) => new NotExp(e); 101 } 102 103 Parser boolCmp() 104 { 105 return (arithExp() + (new Reserved("<") | new Reserved("<=") 106 | new Reserved(">") | new Reserved(">=") 107 | new Reserved("=") | new Reserved("!=")) + arithExp()) 108 ^ (Expression l, Keyword op, Expression r) => new CmpExp(op.value, l, r); 109 } 110 111 Parser boolGroup() 112 { 113 return (new Reserved("(") + new Lazy(&boolExp) + new Reserved(")")) 114 ^ (Keyword b0, Expression e, Keyword b1) => e; 115 } 116 117 /// Aritmetic Expressions 118 119 Parser arithExp() 120 { 121 return (arithTerm() * (new Reserved("/") | new Reserved("*") | new Reserved("+") | new Reserved("-"))) 122 & (Expression l, Keyword op, Expression r) => new BinExp(op.value, l, r); 123 } 124 125 Parser arithTerm() 126 { 127 return arithValue() | arithGroup(); 128 } 129 130 Parser arithGroup() 131 { 132 return (new Reserved("(") + new Lazy(&arithExp) + new Reserved(")")) 133 ^ (Keyword b0, Expression e, Keyword b1) => e; 134 } 135 136 Parser arithValue() 137 { 138 return valueInt() | valueIdent(); 139 } 140 141 /// Value types. 142 143 Parser valueInt() 144 { 145 return new TokenTag(Tag.Integer) 146 ^ (TokenClass e) 147 { 148 static IntegerExp[string] icache; 149 150 if (e.value !in icache) 151 icache[e.value] = new IntegerExp(e.value); 152 153 return icache[e.value]; 154 }; 155 } 156 157 Parser valueIdent() 158 { 159 return new TokenTag(Tag.Identifier) 160 ^ (TokenClass e) 161 { 162 static VarExp[string] vcache; 163 164 if (e.value !in vcache) 165 vcache[e.value] = new VarExp(e.value); 166 167 return vcache[e.value]; 168 }; 169 }