Skip to content

Instantly share code, notes, and snippets.

@BSFishy
Last active September 23, 2026 17:39
Show Gist options
  • Select an option

  • Save BSFishy/10da08a6a0b8f43175eeb31a76d196c4 to your computer and use it in GitHub Desktop.

Select an option

Save BSFishy/10da08a6a0b8f43175eeb31a76d196c4 to your computer and use it in GitHub Desktop.
recursive descent parser
public class Parser {
List<Token> tokens;
int position = 0;
private Token consume() {
int pos = this.position;
this.position++;
return this.tokens.get(pos);
}
private Token eat(Tokens tokenType) {
Token token = this.consume();
if (token.id != tokenType) {
throw new NoMatchException();
}
return token;
}
private <T> T attempt(ParseFunction<T> func) {
int mark = this.position;
try {
return func.parse();
} catch (NoMatchException _e) {
this.position = mark;
return null;
}
}
public File file() {
List<Statement> statements = new ArrayList<Statement>();
while (true) {
Statement statement = this.statement();
if (statement == null) {
break;
}
statements.add(statement);
}
return new File(statements);
}
public Statement statement() {
Expression expr = this.expression();
this.eat(Tokens.SEMICOLON);
return new Statement(expr);
}
public Expression expression() {
Token token = this.consume();
switch (token.id) {
case Tokens.IDENTIFIER:
Arguments args = this.attempt(this.args);
if (args != null) {
return new Call(token, args);
}
return new Expression(ExpressionType.IDENTIFIER, token);
case Tokens.NUMBER:
return new Expression(ExpressionType.NUMBER, token);
default:
throw new NoMatchException();
}
}
public Arguments args() {
this.eat(Tokens.LPAREN);
// argument list...
this.eat(Tokens.RPAREN);
return new Arguments();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment