Parsing Expressions 6
This commit is contained in:
parent
2de4381fae
commit
d937226553
5 changed files with 177 additions and 6 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -14,3 +14,6 @@ lox-test-*
|
|||
*.o
|
||||
*.obj
|
||||
*.lst
|
||||
|
||||
.msc/
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import taggedalgebraic;
|
|||
|
||||
import jlox.token;
|
||||
import jlox.tokentype;
|
||||
import jlox.util;
|
||||
|
||||
abstract class Expr{
|
||||
interface Visitor(R){
|
||||
|
|
@ -20,10 +21,7 @@ abstract class Expr{
|
|||
static foreach(T; rTypes)
|
||||
abstract T accept(Visitor!T visitor);
|
||||
private template defCtorAndAccept(){
|
||||
this(Args...)(auto ref Args args){
|
||||
static foreach(i, a; args)
|
||||
this.tupleof[i] = a;
|
||||
}
|
||||
mixin defaultCtor;
|
||||
static foreach(T; rTypes)
|
||||
override T accept(Visitor!T visitor) => visitor.visit(this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,12 +10,21 @@ import commandr;
|
|||
import jlox.token;
|
||||
import jlox.tokentype;
|
||||
import jlox.scanner;
|
||||
import jlox.parser;
|
||||
import jlox.expr;
|
||||
|
||||
static bool hadError = false;
|
||||
|
||||
void error(int line, string message){
|
||||
report(line, "", message);
|
||||
}
|
||||
void error(Token token, string message){
|
||||
if (token.type == TokenType.EOF) {
|
||||
report(token.line, " at end", message);
|
||||
} else {
|
||||
report(token.line, " at '" ~ token.lexeme ~ "'", message);
|
||||
}
|
||||
}
|
||||
void report(int line, string where, string message){
|
||||
stderr.writeln("[line " ~ line.to!string ~ "] Error" ~ where ~ ": " ~ message);
|
||||
hadError = true;
|
||||
|
|
@ -25,8 +34,13 @@ void run(string source){
|
|||
Scanner scanner = new Scanner(source);
|
||||
Token[] tokens = scanner.scanTokens();
|
||||
|
||||
foreach(token; tokens)
|
||||
writeln(token);
|
||||
Parser parser = new Parser(tokens);
|
||||
Expr expression = parser.parse();
|
||||
|
||||
if(hadError)
|
||||
return;
|
||||
|
||||
writeln((new AstPrinter).print(expression));
|
||||
}
|
||||
|
||||
void runFile(string path){
|
||||
|
|
|
|||
148
src/jlox/parser.d
Normal file
148
src/jlox/parser.d
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
module jlox.parser;
|
||||
|
||||
import std.stdio;
|
||||
|
||||
import jlox.token;
|
||||
import jlox.tokentype;
|
||||
import jlox.util;
|
||||
import jlox.expr;
|
||||
import jlox.main : loxError = error;
|
||||
|
||||
class Parser{
|
||||
private Token[] tokens;
|
||||
private int current = 0;
|
||||
|
||||
mixin defaultCtor;
|
||||
Expr parse(){
|
||||
try {
|
||||
return expression();
|
||||
} catch (ParseError error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private bool isAtEnd() => peek().type == EOF;
|
||||
private Token peek() => tokens[current];
|
||||
private Token previous() => tokens[current-1];
|
||||
private bool check(TokenType type){
|
||||
if(isAtEnd)
|
||||
return false;
|
||||
return peek().type == type;
|
||||
}
|
||||
private Token advance(){
|
||||
if(!isAtEnd())
|
||||
current++;
|
||||
return previous();
|
||||
}
|
||||
private bool match(TokenType[] types...){
|
||||
foreach(TokenType type; types){
|
||||
if(check(type)){
|
||||
advance();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private Token consume(TokenType type, string message){
|
||||
if(check(type))
|
||||
return advance();
|
||||
throw error(peek(), message);
|
||||
}
|
||||
private static class ParseError : Exception {
|
||||
this(string s){
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
private ParseError error(Token token, string message){
|
||||
loxError(token, message);
|
||||
return new ParseError("hello");
|
||||
}
|
||||
private void synchronize(){
|
||||
advance();
|
||||
with(TokenType) while(!isAtEnd()){
|
||||
if(previous().type == SEMICOLON)
|
||||
return;
|
||||
switch(peek().type){
|
||||
case CLASS:
|
||||
case FUN:
|
||||
case VAR:
|
||||
case FOR:
|
||||
case IF:
|
||||
case WHILE:
|
||||
case PRINT:
|
||||
case RETURN:
|
||||
return;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
advance();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Expr expression(){
|
||||
return equality();
|
||||
}
|
||||
private Expr equality(){
|
||||
Expr expr = comparison();
|
||||
while(match(TokenType.BANG_EQUAL, TokenType.EQUAL_EQUAL)){
|
||||
Token operator = previous();
|
||||
Expr right = comparison();
|
||||
expr = new Expr.Binary(expr, operator, right);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
private Expr comparison(){
|
||||
Expr expr = term();
|
||||
while(match(TokenType.GREATER, TokenType.GREATER_EQUAL, TokenType.LESS, TokenType.LESS_EQUAL)){
|
||||
Token operator = previous();
|
||||
Expr right = term();
|
||||
expr = new Expr.Binary(expr, operator, right);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
private Expr term(){
|
||||
Expr expr = factor();
|
||||
while(match(TokenType.MINUS, TokenType.PLUS)){
|
||||
Token operator = previous();
|
||||
Expr right = factor();
|
||||
expr = new Expr.Binary(expr, operator, right);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
private Expr factor(){
|
||||
Expr expr = unary();
|
||||
while(match(TokenType.SLASH, TokenType.STAR)){
|
||||
Token operator = previous();
|
||||
Expr right = unary();
|
||||
expr = new Expr.Binary(expr, operator, right);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
private Expr unary(){
|
||||
if(match(TokenType.BANG, TokenType.MINUS)){
|
||||
Token operator = previous();
|
||||
Expr right = unary();
|
||||
return new Expr.Unary(operator, right);
|
||||
}
|
||||
return primary();
|
||||
}
|
||||
private Expr primary(){
|
||||
if(match(TokenType.FALSE))
|
||||
return new Expr.Literal(false);
|
||||
if(match(TokenType.TRUE))
|
||||
return new Expr.Literal(true);
|
||||
if(match(TokenType.NIL))
|
||||
return new Expr.Literal(null);
|
||||
if(match(TokenType.NUMBER, TokenType.STRING))
|
||||
return new Expr.Literal(previous().literal);
|
||||
if(match(TokenType.LEFT_PAREN)){
|
||||
Expr expr = expression();
|
||||
consume(TokenType.RIGHT_PAREN, "Expect ')' after expression.");
|
||||
return new Expr.Grouping(expr);
|
||||
}
|
||||
throw error(peek(), "Expect expression.");
|
||||
assert(0);
|
||||
}
|
||||
|
||||
}
|
||||
8
src/jlox/util.d
Normal file
8
src/jlox/util.d
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
module jlox.util;
|
||||
|
||||
template defaultCtor(){
|
||||
this(Args...)(auto ref Args args){
|
||||
static foreach(i, a; args)
|
||||
this.tupleof[i] = a;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue