Parsodus/examples/calc/parser.cpp

186 lines
6.7 KiB
C++

/*
* Parsodus - A language agnostic parser generator
* Copyright © 2016-2017 Thomas Avé, Robin Jadoul, Kobe Wullaert
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "parser.h"
#include <iostream>
namespace calc {
Parser::Parser(CalcLexer lex) : m_lex(lex) {
std::cout << ">>> ";
std::cout.flush();
}
Parser::Token Parser::lex() {
while (true) {
try {
CalcLexer::Token orig = m_lex.nextToken();
Token ret{calcParser_Symbol::T_EOF, nullptr};
if (orig.type == CalcLexer::NUM) {
ret = { calcParser_Symbol::T_NUM, std::make_unique<Number>(std::stod(orig.content)) };
} else if (orig.type == CalcLexer::IDENT) {
ret = { calcParser_Symbol::T_IDENT, std::make_unique<Var>(orig.content) };
} else {
ret = { static_cast<calcParser_Symbol>(orig.type), nullptr };
}
return ret;
}
catch (CalcLexer::NoMoreTokens) {
return { calcParser_Symbol::T_EOF, nullptr };
}
catch (CalcLexer::NoMatch) {
m_lex.skip(1);
return { calcParser_Symbol::V_error, nullptr }; //Somewhat dependent on the generated code, but this should always give an error
}
}
}
Parser::Value Parser::error(Token, const std::vector<calcParser_Symbol>&) {
return nullptr;
}
Parser::Value Parser::reduce_toplevel(std::deque<Token> subparts) {
if (subparts.empty()) return nullptr;
if (subparts[0].symbol == calcParser_Symbol::V_expr) {
std::cout << "\033[3;34m => " << subparts[0].value->eval(m_variables, m_functions) << "\033[0m" << std::endl;
} else if (subparts[0].symbol == calcParser_Symbol::V_error) {
std::cout << "\033[3;31m => <syntax error>" << "\033[0m" << std::endl;
}
try {
if (m_lex.peek() == '\n') {
std::cout << ">>> ";
std::cout.flush();
}
}
catch (CalcLexer::NoMoreTokens) {}
return nullptr;
}
Parser::Value Parser::reduce_binop(std::deque<Token> subparts) {
std::string op;
switch (subparts[1].symbol) {
case calcParser_Symbol::T_PLUS:
op = "+";
break;
case calcParser_Symbol::T_MINUS:
op = "-";
break;
case calcParser_Symbol::T_TIMES:
op = "*";
break;
case calcParser_Symbol::T_DIVIDE:
op = "/";
break;
case calcParser_Symbol::T_EXPONENT:
op = "^";
break;
case calcParser_Symbol::T_LT:
op = "<";
break;
default:
break;
}
return std::make_unique<Binop>(std::move(subparts[0].value), op, std::move(subparts[2].value));
}
Parser::Value Parser::reduce_expr_simple(std::deque<Token> subparts) {
return std::move(subparts[0].value);
}
Parser::Value Parser::reduce_umin(std::deque<Token> subparts) {
return std::make_unique<Unop>("-", std::move(subparts[1].value));
}
Parser::Value Parser::reduce_parenthesized(std::deque<Token> subparts) {
return std::move(subparts[1].value);
}
Parser::Value Parser::reduce_functioncall(std::deque<Token> subparts) {
auto args = dynamic_cast<FunctionArguments*>(subparts[2].value.get());
subparts[2].value.release();
return std::make_unique<FunctionCall>(dynamic_cast<Var*>(subparts[0].value.get())->getName(), std::unique_ptr<FunctionArguments>(args));
}
Parser::Value Parser::reduce_opt_arguments(std::deque<Token> subparts) {
if (subparts.size()) {
return std::move(subparts[0].value);
} else {
return std::make_unique<FunctionArguments>();
}
}
Parser::Value Parser::reduce_arguments(std::deque<Token> subparts) {
std::unique_ptr<FunctionArguments> args;
if (subparts.size() > 1) {
args = std::unique_ptr<FunctionArguments>(dynamic_cast<FunctionArguments*>(subparts[0].value.get()));
subparts[0].value.release();
} else {
args = std::make_unique<FunctionArguments>();
}
args->push_back(std::move(subparts[subparts.size() - 1].value));
return args;
}
Parser::Value Parser::reduce_functiondef(std::deque<Token> subparts) {
std::string name = dynamic_cast<Var*>(subparts[1].value.get())->getName();
std::deque<std::string> formalParams;
FormalParameters* fp = dynamic_cast<FormalParameters*>(subparts[3].value.get());
for (const std::unique_ptr<AST>& param : *fp) {
formalParams.push_back(dynamic_cast<Var*>(param.get())->getName());
}
m_functions[name] = std::make_unique<Function>(std::move(formalParams), std::move(subparts[6].value));
std::cout << "\033[3;32m => Function " << name << " defined.\033[0m" << std::endl;
return nullptr;
}
Parser::Value Parser::reduce_opt_idents(std::deque<Token> subparts) {
if (subparts.size()) {
return std::move(subparts[0].value);
} else {
return std::make_unique<FormalParameters>();
}
}
Parser::Value Parser::reduce_idents(std::deque<Token> subparts) {
std::unique_ptr<FormalParameters> args;
if (subparts.size() > 1) {
args = std::unique_ptr<FormalParameters>(dynamic_cast<FormalParameters*>(subparts[0].value.get()));
subparts[0].value.release();
} else {
args = std::make_unique<FormalParameters>();
}
args->push_back(std::move(subparts[subparts.size() - 1].value));
return args;
}
Parser::Value Parser::reduce_assign(std::deque<Token> subparts) {
std::string name = dynamic_cast<Var*>(subparts[0].value.get())->getName();
m_variables[name] = subparts[2].value->eval(m_variables, m_functions);
std::cout << "\033[3;34m => " << name << " = " << m_variables[name] << "\033[0m" <<std::endl;
return nullptr;
}
} /* calc */