parser: initial expression parser
This commit is contained in:
parent
e2f587437d
commit
b6d4ae5e8e
12
error.hpp
12
error.hpp
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
namespace dsp {
|
||||
|
||||
@ -21,4 +22,15 @@ static inline void error(const int line, const int col, std::string message)
|
||||
report(line, col, "", message);
|
||||
}
|
||||
|
||||
static inline void error(const token_t& token, const std::string message)
|
||||
{
|
||||
using enum token_t::type_t;
|
||||
|
||||
if (token.type == eof) {
|
||||
report(token.pos.line, token.pos.col, " at end", message);
|
||||
} else {
|
||||
report(token.pos.line, token.pos.col, " at '" + std::string(token.lexeme) + "'", message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
6
expr.hpp
6
expr.hpp
@ -52,11 +52,11 @@ struct literal_t : expr_accept_t<literal_t>
|
||||
|
||||
struct unary_t : expr_accept_t<unary_t>
|
||||
{
|
||||
unary_t(token_t oper, expr_t * expr)
|
||||
: oper(oper), expr(expr) {}
|
||||
unary_t(token_t oper, expr_t * right)
|
||||
: oper(oper), right(right) {}
|
||||
|
||||
const token_t oper;
|
||||
const expr_t * expr;
|
||||
const expr_t * right;
|
||||
};
|
||||
|
||||
}
|
||||
|
160
parser.cpp
160
parser.cpp
@ -1,4 +1,162 @@
|
||||
struct parser_t
|
||||
/*
|
||||
expression → term ;
|
||||
term → factor ( ( "-" | "+" ) factor )* ;
|
||||
factor → unary ( ( "/" | "*" | "%" ) unary )* ;
|
||||
unary → ( "~" | "+" | "-" ) unary
|
||||
| shift ;
|
||||
shift → andl ( ( "<<" | ">>" ) andl )*
|
||||
andl → orl ( "&" orl )*
|
||||
orl → andl ( ( "|" | "^" ) andl )*
|
||||
primary → NUMBER
|
||||
| "(" expression ")" ;
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "parser.hpp"
|
||||
#include "num.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
namespace dsp {
|
||||
|
||||
using enum token_t::type_t;
|
||||
|
||||
bool parser_t::at_end_p()
|
||||
{
|
||||
return peek().type == eof;
|
||||
}
|
||||
|
||||
parse_error_t parser_t::error(const token_t& token, const std::string message)
|
||||
{
|
||||
dsp::error(token, message);
|
||||
return parse_error_t(message);
|
||||
}
|
||||
|
||||
token_t& parser_t::previous()
|
||||
{
|
||||
return tokens[current_ix-1];
|
||||
}
|
||||
|
||||
token_t& parser_t::peek()
|
||||
{
|
||||
return tokens[current_ix];
|
||||
}
|
||||
|
||||
token_t& parser_t::advance()
|
||||
{
|
||||
if (!at_end_p()) current_ix++;
|
||||
return previous();
|
||||
}
|
||||
|
||||
bool parser_t::check(enum token_t::type_t token_type)
|
||||
{
|
||||
if (at_end_p()) return false;
|
||||
return peek().type == token_type;
|
||||
}
|
||||
|
||||
bool parser_t::match(enum token_t::type_t token_type)
|
||||
{
|
||||
if (check(token_type)) {
|
||||
advance();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename... Targs>
|
||||
bool parser_t::match(enum token_t::type_t token_type, Targs... args)
|
||||
{
|
||||
return match(token_type) || match(args...);
|
||||
}
|
||||
|
||||
token_t parser_t::consume(enum token_t::type_t token_type, const std::string error_message)
|
||||
{
|
||||
if (check(token_type)) return advance();
|
||||
|
||||
throw error(peek(), error_message);
|
||||
}
|
||||
|
||||
expr_t * parser_t::expression()
|
||||
{
|
||||
return term();
|
||||
}
|
||||
|
||||
expr_t * parser_t::term()
|
||||
{
|
||||
expr_t * left = factor();
|
||||
while (match(minus, plus)) {
|
||||
token_t oper = previous();
|
||||
expr_t * right = factor();
|
||||
left = new binary_t(left, oper, right);
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
expr_t * parser_t::factor()
|
||||
{
|
||||
expr_t * left = unary();
|
||||
while (match(slash, star, percent)) {
|
||||
token_t oper = previous();
|
||||
expr_t * right = unary();
|
||||
left = new binary_t(left, oper, right);
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
expr_t * parser_t::unary()
|
||||
{
|
||||
if (match(tilde, plus, minus)) {
|
||||
token_t oper = previous();
|
||||
expr_t * right = unary();
|
||||
return new unary_t(oper, right);
|
||||
}
|
||||
return shift();
|
||||
}
|
||||
|
||||
expr_t * parser_t::shift()
|
||||
{
|
||||
expr_t * left = andl();
|
||||
while (match(left_shift, right_shift)) {
|
||||
token_t oper = previous();
|
||||
expr_t * right = andl();
|
||||
left = new binary_t(left, oper, right);
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
expr_t * parser_t::andl()
|
||||
{
|
||||
expr_t * left = orl();
|
||||
while (match(ampersand)) {
|
||||
token_t oper = previous();
|
||||
expr_t * right = orl();
|
||||
left = new binary_t(left, oper, right);
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
expr_t * parser_t::orl()
|
||||
{
|
||||
expr_t * left = primary();
|
||||
while (match(bar, carot)) {
|
||||
token_t oper = previous();
|
||||
expr_t * right = primary();
|
||||
left = new binary_t(left, oper, right);
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
expr_t * parser_t::primary()
|
||||
{
|
||||
if (match(number)) return new literal_t(std::get<num_t>(previous().literal));
|
||||
|
||||
if (match(left_paren)) {
|
||||
expr_t * expr = expression();
|
||||
consume(right_paren, "expected ')' after expression.");
|
||||
return new grouping_t(expr);
|
||||
}
|
||||
|
||||
throw error(peek(), "expected expression");
|
||||
}
|
||||
|
||||
}
|
||||
|
50
parser.hpp
Normal file
50
parser.hpp
Normal file
@ -0,0 +1,50 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "token.hpp"
|
||||
#include "expr.hpp"
|
||||
|
||||
namespace dsp {
|
||||
|
||||
struct parse_error_t : std::runtime_error
|
||||
{
|
||||
parse_error_t(const std::string& msg)
|
||||
: std::runtime_error(msg)
|
||||
{ }
|
||||
};
|
||||
|
||||
struct parser_t
|
||||
{
|
||||
int current_ix = 0;
|
||||
std::vector<token_t> tokens;
|
||||
|
||||
parser_t(const std::vector<token_t>& tokens)
|
||||
: tokens(tokens)
|
||||
{ }
|
||||
|
||||
static parse_error_t error(const token_t& token, const std::string message);
|
||||
|
||||
bool at_end_p();
|
||||
|
||||
token_t& previous();
|
||||
token_t& peek();
|
||||
token_t& advance();
|
||||
bool check(enum token_t::type_t token_type);
|
||||
bool match(enum token_t::type_t token_type);
|
||||
template <typename... Targs>
|
||||
bool match(enum token_t::type_t token_type, Targs... args);
|
||||
token_t consume(enum token_t::type_t token_type, const std::string error_message);
|
||||
|
||||
expr_t * expression();
|
||||
expr_t * term();
|
||||
expr_t * factor();
|
||||
expr_t * unary();
|
||||
expr_t * shift();
|
||||
expr_t * andl();
|
||||
expr_t * orl();
|
||||
expr_t * primary();
|
||||
|
||||
};
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user