ADD: int arithmetic.

main
bog 2023-08-31 00:31:19 +02:00
parent fbbbd4e9f4
commit 051b696b26
22 changed files with 475 additions and 40 deletions

View File

@ -1,4 +1,11 @@
PROG ::= (INSTR (EOI INSTR)*)? PROG ::= (INSTR (EOI INSTR)*)?
INSTR ::= EXPR INSTR ::= EXPR
EXPR ::= BASE EXPR ::= TERM
TERM ::= FACTOR ((add | sub) FACTOR)*
FACTOR ::= UNOP ((mul | div | mod) UNOP)*
UNOP ::= (add | sub)? POW
POW ::= GROUP (pow GROUP)?
GROUP ::= BASE | opar EXPR cpar
BASE ::= int BASE ::= int

View File

@ -28,13 +28,48 @@ namespace roza
prog->push_instr(OP_PUSH_CONST, prog->push_value(value)); prog->push_instr(OP_PUSH_CONST, prog->push_value(value));
} break; } break;
case NODE_PROG: { case NODE_ADD: {
compile_children(root, prog); compile_children(root, prog);
prog->push_instr(OP_IADD);
} break; } break;
case NODE_INSTR: { case NODE_SUB: {
compile_children(root, prog);
prog->push_instr(OP_ISUB);
} break;
case NODE_MUL: {
compile_children(root, prog);
prog->push_instr(OP_IMUL);
} break;
case NODE_DIV: {
compile_children(root, prog);
prog->push_instr(OP_IDIV);
} break;
case NODE_MOD: {
compile_children(root, prog);
prog->push_instr(OP_IMOD);
} break;
case NODE_POW: {
compile_children(root, prog);
prog->push_instr(OP_IPOW);
} break;
case NODE_UADD: {
compile_children(root, prog);
prog->push_instr(OP_IUADD);
} break;
case NODE_USUB: {
compile_children(root, prog);
prog->push_instr(OP_IUSUB);
} break;
case NODE_PROG: {
compile_children(root, prog); compile_children(root, prog);
prog->push_instr(OP_POP);
} break; } break;
default: default:

View File

@ -8,12 +8,26 @@ namespace roza
, m_loc { loc } , m_loc { loc }
{ {
m_scanners.push_back(std::bind(&Lexer::scan_int, this)); m_scanners.push_back(std::bind(&Lexer::scan_int, this));
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "+", NODE_ADD, false));
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "-", NODE_SUB, false));
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "*", NODE_MUL, false));
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "/", NODE_DIV, false));
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "%", NODE_MOD, false));
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "^", NODE_POW, false));
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "(", NODE_OPAR, false));
m_scanners.push_back(std::bind(&Lexer::scan_text, this, ")", NODE_CPAR, false));
} }
/*virtual*/ Lexer::~Lexer() /*virtual*/ Lexer::~Lexer()
{ {
} }
bool Lexer::is_at_end() const
{
return m_cursor >= size();
}
void Lexer::scan(std::string const& source) void Lexer::scan(std::string const& source)
{ {
m_source = source; m_source = source;
@ -32,6 +46,7 @@ namespace roza
m_cursor++; m_cursor++;
} }
m_loc.set_line(m_loc.line() + 1);
m_cursor++; m_cursor++;
} }
@ -108,12 +123,6 @@ namespace roza
size_t cursor = m_cursor; size_t cursor = m_cursor;
std::string repr; std::string repr;
if (m_source[cursor] == '-')
{
repr += "-";
cursor++;
}
while (cursor < m_source.size() while (cursor < m_source.size()
&& std::isdigit(m_source[cursor])) && std::isdigit(m_source[cursor]))
{ {
@ -131,4 +140,24 @@ namespace roza
return ScanInfo {}; return ScanInfo {};
} }
ScanInfo Lexer::scan_text(std::string const& text
, NodeType type
, bool value) const
{
for (size_t i=0; i<text.size(); i++)
{
if (m_cursor + i >= m_source.size()
|| m_source[m_cursor + i] != text[i])
{
return ScanInfo {
};
}
}
return ScanInfo {
std::make_shared<Node>(type, value ? text : "", m_loc),
m_cursor + text.size()
};
}
} }

View File

@ -24,6 +24,7 @@ namespace roza
SrcLoc loc() const { return m_loc; } SrcLoc loc() const { return m_loc; }
size_t size() const { return m_nodes.size(); } size_t size() const { return m_nodes.size(); }
bool is_at_end() const;
void scan(std::string const& source); void scan(std::string const& source);
void skip_blanks(); void skip_blanks();
std::shared_ptr<Node> get_or_nullptr(size_t index) const; std::shared_ptr<Node> get_or_nullptr(size_t index) const;
@ -38,6 +39,9 @@ namespace roza
std::vector<scanner> m_scanners; std::vector<scanner> m_scanners;
ScanInfo scan_int() const; ScanInfo scan_int() const;
ScanInfo scan_text(std::string const& text,
NodeType type,
bool value=false) const;
}; };
} }

View File

@ -4,9 +4,11 @@
#include "commons.hpp" #include "commons.hpp"
#include "SrcLoc.hpp" #include "SrcLoc.hpp"
#define NODE_TYPE(G) \ #define NODE_TYPE(G) \
G(NODE_PROG), G(NODE_INSTR), G(NODE_EOI), \ G(NODE_PROG), G(NODE_INSTR), G(NODE_EOI), \
G(NODE_INT) G(NODE_INT), G(NODE_ADD), G(NODE_SUB), G(NODE_MUL), \
G(NODE_DIV), G(NODE_MOD), G(NODE_POW), G(NODE_OPAR), \
G(NODE_CPAR), G(NODE_UADD), G(NODE_USUB)
namespace roza namespace roza
{ {

View File

@ -20,7 +20,7 @@ namespace roza
if (m_cursor < m_lexer.size()) if (m_cursor < m_lexer.size())
{ {
m_log.fatal(m_lexer.loc(), "unexpected end."); m_log.fatal(m_lexer.loc(), "unexpected end");
} }
return root; return root;
@ -46,6 +46,16 @@ namespace roza
return tok->type() == type; return tok->type() == type;
} }
std::shared_ptr<Node> Parser::consume_or_nullptr(NodeType ty)
{
if (m_cursor >= m_lexer.size())
{
return nullptr;
}
return consume(ty);
}
std::shared_ptr<Node> Parser::consume(NodeType ty) std::shared_ptr<Node> Parser::consume(NodeType ty)
{ {
if (!type_is(ty)) if (!type_is(ty))
@ -66,6 +76,22 @@ namespace roza
return ret; return ret;
} }
void Parser::consume_all(NodeType ty)
{
while (type_is(ty))
{
next();
}
}
std::shared_ptr<Node> Parser::consume()
{
auto ret = node();
next();
return ret;
}
void Parser::next() void Parser::next()
{ {
m_cursor++; m_cursor++;
@ -81,9 +107,8 @@ namespace roza
auto root = std::make_shared<Node>(NODE_PROG, "", node()->loc()); auto root = std::make_shared<Node>(NODE_PROG, "", node()->loc());
root->add_child(parse_instr()); root->add_child(parse_instr());
while (type_is(NODE_EOI)) while (m_cursor < m_lexer.size())
{ {
next();
root->add_child(parse_instr()); root->add_child(parse_instr());
} }
@ -92,16 +117,98 @@ namespace roza
std::shared_ptr<Node> Parser::parse_instr() std::shared_ptr<Node> Parser::parse_instr()
{ {
auto lhs = parse_expr(); auto root = parse_expr();
consume_or_nullptr(NODE_EOI);
auto root = std::make_shared<Node>(NODE_INSTR, "", lhs->loc()); consume_all(NODE_EOI);
root->add_child(lhs);
return root; return root;
} }
std::shared_ptr<Node> Parser::parse_expr() std::shared_ptr<Node> Parser::parse_expr()
{ {
return parse_term();
}
std::shared_ptr<Node> Parser::parse_term()
{
auto lhs = parse_factor();
while (type_is(NODE_ADD) || type_is(NODE_SUB))
{
auto root = consume();
root->add_child(lhs);
root->add_child(parse_factor());
lhs = root;
}
return lhs;
}
std::shared_ptr<Node> Parser::parse_factor()
{
auto lhs = parse_unop();
while (type_is(NODE_MUL)
|| type_is(NODE_DIV)
|| type_is(NODE_MOD))
{
auto root = consume();
root->add_child(lhs);
root->add_child(parse_unop());
lhs = root;
}
return lhs;
}
std::shared_ptr<Node> Parser::parse_unop()
{
if (type_is(NODE_ADD))
{
auto root = std::make_shared<Node>(NODE_UADD, "", m_lexer.loc());
next();
root->add_child(parse_pow());
return root;
}
if (type_is(NODE_SUB))
{
auto root = std::make_shared<Node>(NODE_USUB, "", m_lexer.loc());
next();
root->add_child(parse_pow());
return root;
}
return parse_pow();
}
std::shared_ptr<Node> Parser::parse_pow()
{
auto lhs = parse_group();
if (type_is(NODE_POW))
{
auto root = consume();
root->add_child(lhs);
root->add_child(parse_group());
lhs = root;
}
return lhs;
}
std::shared_ptr<Node> Parser::parse_group()
{
if (type_is(NODE_OPAR))
{
consume(NODE_OPAR);
auto root = parse_expr();
consume(NODE_CPAR);
return root;
}
return parse_base(); return parse_base();
} }

View File

@ -23,12 +23,20 @@ namespace roza
std::shared_ptr<Node> node(size_t offset=0) const; std::shared_ptr<Node> node(size_t offset=0) const;
NodeType type(size_t offset=0) const; NodeType type(size_t offset=0) const;
bool type_is(NodeType type, size_t offset=0) const; bool type_is(NodeType type, size_t offset=0) const;
std::shared_ptr<Node> consume_or_nullptr(NodeType type);
std::shared_ptr<Node> consume(NodeType type); std::shared_ptr<Node> consume(NodeType type);
void consume_all(NodeType type);
std::shared_ptr<Node> consume();
void next(); void next();
std::shared_ptr<Node> parse_prog(); std::shared_ptr<Node> parse_prog();
std::shared_ptr<Node> parse_instr(); std::shared_ptr<Node> parse_instr();
std::shared_ptr<Node> parse_expr(); std::shared_ptr<Node> parse_expr();
std::shared_ptr<Node> parse_term();
std::shared_ptr<Node> parse_factor();
std::shared_ptr<Node> parse_unop();
std::shared_ptr<Node> parse_pow();
std::shared_ptr<Node> parse_group();
std::shared_ptr<Node> parse_base(); std::shared_ptr<Node> parse_base();
std::shared_ptr<Node> parse_int(); std::shared_ptr<Node> parse_int();

View File

@ -34,6 +34,17 @@ namespace roza
return m_instrs[index].param; return m_instrs[index].param;
} }
std::shared_ptr<Value> Program::value(size_t index) const
{
assert(has_value(index));
return m_values[index];
}
bool Program::has_value(size_t index) const
{
return index < m_values.size();
}
std::string Program::string() const std::string Program::string() const
{ {
std::stringstream ss; std::stringstream ss;
@ -41,12 +52,22 @@ namespace roza
for (auto const& instr: m_instrs) for (auto const& instr: m_instrs)
{ {
ss << addr ss << addr++
<< "\t" << "\t"
<< (OpcodeStr[instr.opcode]) << (OpcodeStr[instr.opcode])
<< "\t" << "\t";
<< (instr.param != std::nullopt ? std::to_string(*instr.param) : "")
<< "\n"; if (instr.param)
{
ss << std::to_string(*instr.param);
if (has_value(*instr.param))
{
ss << "\t" << "(" << value(*instr.param)->string() << ")";
}
}
ss << "\n";
} }
return ss.str(); return ss.str();

View File

@ -27,6 +27,8 @@ namespace roza
Opcode opcode(size_t index) const; Opcode opcode(size_t index) const;
std::optional<param_t> param(size_t index) const; std::optional<param_t> param(size_t index) const;
std::shared_ptr<Value> value(size_t index) const;
bool has_value(size_t index) const;
std::string string() const; std::string string() const;

View File

@ -1,5 +1,6 @@
#include "StaticPass.hpp" #include "StaticPass.hpp"
#include "lib/Node.hpp" #include "lib/Node.hpp"
#include "TypeResolver.hpp"
namespace roza namespace roza
{ {
@ -14,12 +15,39 @@ namespace roza
void StaticPass::check(std::shared_ptr<Node> root) void StaticPass::check(std::shared_ptr<Node> root)
{ {
TypeResolver resolver {m_log};
switch (root->type()) switch (root->type())
{ {
case NODE_INT: break; case NODE_INT: break;
case NODE_PROG: case NODE_ADD:
case NODE_INSTR: { case NODE_SUB:
case NODE_MUL:
case NODE_DIV:
case NODE_MOD:
case NODE_POW: {
auto lhs = resolver.find(root->child(0));
auto rhs = resolver.find(root->child(1));
if (!lhs->equals(*rhs))
{
m_log.fatal(root->loc(),
std::string()
+ "type mismatch, expected '"
+ lhs->string()
+ "', got '"
+ rhs->string()
+ "'");
}
} break;
case NODE_UADD:
case NODE_USUB: {
} break;
case NODE_PROG: {
for (size_t i=0; i<root->size(); i++) for (size_t i=0; i<root->size(); i++)
{ {
check(root->child(i)); check(root->child(i));

View File

@ -11,6 +11,12 @@ namespace roza
{ {
} }
std::string Type::string() const
{
return std::string(BaseTypeStr[m_base])
.substr(std::string("TY_").size());
}
bool Type::equals(BaseType rhs) const bool Type::equals(BaseType rhs) const
{ {
return m_base == rhs; return m_base == rhs;

View File

@ -18,6 +18,8 @@ namespace roza
BaseType base() const { return m_base; } BaseType base() const { return m_base; }
std::string string() const;
bool equals(BaseType rhs) const; bool equals(BaseType rhs) const;
bool equals(Type const& rhs) const; bool equals(Type const& rhs) const;

View File

@ -15,8 +15,7 @@ namespace roza
{ {
switch (root->type()) switch (root->type())
{ {
case NODE_PROG: case NODE_PROG: {
case NODE_INSTR: {
return find(root->child(root->size() - 1)); return find(root->child(root->size() - 1));
} break; } break;
@ -24,6 +23,17 @@ namespace roza
return std::make_shared<Type>(BaseType::TY_INT); return std::make_shared<Type>(BaseType::TY_INT);
} break; } break;
case NODE_ADD:
case NODE_SUB:
case NODE_MUL:
case NODE_DIV:
case NODE_MOD:
case NODE_POW:
case NODE_UADD:
case NODE_USUB:{
return find(root->child(0));
} break;
default: default:
m_log.fatal(root->loc(), "cannot find type of node '" + root->string() + "'"); m_log.fatal(root->loc(), "cannot find type of node '" + root->string() + "'");
} }

View File

@ -1,4 +1,5 @@
#include "VM.hpp" #include "VM.hpp"
#include "lib/opcodes.hpp"
namespace roza namespace roza
{ {
@ -13,6 +14,7 @@ namespace roza
void VM::exec(std::shared_ptr<Program> program) void VM::exec(std::shared_ptr<Program> program)
{ {
m_last_program = program;
while (m_pc < program->size()) while (m_pc < program->size())
{ {
switch (program->opcode(m_pc)) switch (program->opcode(m_pc))
@ -23,6 +25,61 @@ namespace roza
m_pc++; m_pc++;
} break; } break;
case OP_IADD: {
apply_binop(program, [](auto lhs, auto rhs){
return std::make_shared<Value>(lhs->as_int() + rhs->as_int(),
lhs->loc());
});
} break;
case OP_ISUB: {
apply_binop(program, [](auto lhs, auto rhs){
return std::make_shared<Value>(lhs->as_int() - rhs->as_int(),
lhs->loc());
});
} break;
case OP_IMUL: {
apply_binop(program, [](auto lhs, auto rhs){
return std::make_shared<Value>(lhs->as_int() * rhs->as_int(),
lhs->loc());
});
} break;
case OP_IDIV: {
apply_binop(program, [](auto lhs, auto rhs){
return std::make_shared<Value>(lhs->as_int() / rhs->as_int(),
lhs->loc());
});
} break;
case OP_IMOD: {
apply_binop(program, [](auto lhs, auto rhs){
return std::make_shared<Value>(lhs->as_int() % rhs->as_int(),
lhs->loc());
});
} break;
case OP_IPOW: {
apply_binop(program, [](auto lhs, auto rhs){
return std::make_shared<Value>(std::pow(lhs->as_int(), rhs->as_int()),
lhs->loc());
});
} break;
case OP_IUADD: {
apply_unop(program, [](auto lhs){
return std::make_shared<Value>(lhs->as_int(),
lhs->loc());
});
} break;
case OP_IUSUB: {
apply_unop(program, [](auto lhs){
return std::make_shared<Value>(-lhs->as_int(),
lhs->loc());
});
} break;
case OP_POP: { case OP_POP: {
pop(); pop();
m_pc++; m_pc++;
@ -38,6 +95,31 @@ namespace roza
} }
} }
std::string VM::string() const
{
std::stringstream ss;
for (size_t i=0; i<m_stack.size(); i++)
{
ss << i << "\t";
if (m_last_program && m_last_program->has_value(m_stack[i]))
{
ss << m_stack[i]
<< "\t("
<< m_last_program->value(m_stack[i])->string()
<< ")"
<< std::endl;
}
else
{
ss << m_stack[i] << std::endl;
}
}
return ss.str();
}
void VM::push(param_t param) void VM::push(param_t param)
{ {
m_stack.push_back(param); m_stack.push_back(param);
@ -51,4 +133,25 @@ namespace roza
m_stack.pop_back(); m_stack.pop_back();
return res; return res;
} }
void VM::apply_binop(std::shared_ptr<Program> program, binop_t op)
{
auto rhs = program->value(pop());
auto lhs = program->value(pop());
auto val = op(lhs, rhs);
push(program->push_value(val));
m_pc++;
}
void VM::apply_unop(std::shared_ptr<Program> program, unop_t op)
{
auto lhs = program->value(pop());
auto val = op(lhs);
push(program->push_value(val));
m_pc++;
}
} }

View File

@ -7,6 +7,13 @@
namespace roza namespace roza
{ {
using unop_t = std::function<std::shared_ptr<Value>
(std::shared_ptr<Value>)>;
using binop_t = std::function<std::shared_ptr<Value>
(std::shared_ptr<Value>,
std::shared_ptr<Value>)>;
class VM class VM
{ {
public: public:
@ -14,14 +21,18 @@ namespace roza
virtual ~VM(); virtual ~VM();
void exec(std::shared_ptr<Program> program); void exec(std::shared_ptr<Program> program);
std::string string() const;
private: private:
StatusLog& m_log; StatusLog& m_log;
std::vector<param_t> m_stack; std::vector<param_t> m_stack;
std::shared_ptr<Program> m_last_program;
size_t m_pc = 0; size_t m_pc = 0;
void push(param_t param); void push(param_t param);
param_t pop(); param_t pop();
void apply_binop(std::shared_ptr<Program> program, binop_t op);
void apply_unop(std::shared_ptr<Program> program, unop_t op);
}; };
} }

View File

@ -13,6 +13,8 @@ namespace roza
explicit Value(int value, SrcLoc loc); explicit Value(int value, SrcLoc loc);
virtual ~Value(); virtual ~Value();
SrcLoc loc() const { return m_loc; }
int as_int() const { return m_int_val; }
std::shared_ptr<Type> type() const { return m_type; } std::shared_ptr<Type> type() const { return m_type; }
std::string string() const; std::string string() const;

View File

@ -8,6 +8,7 @@
#include <functional> #include <functional>
#include <optional> #include <optional>
#include <sstream> #include <sstream>
#include <cmath>
#include "mutils.hpp" #include "mutils.hpp"
#endif #endif

View File

@ -5,7 +5,9 @@
#define OPCODE(G) \ #define OPCODE(G) \
G(OP_PUSH_CONST), \ G(OP_PUSH_CONST), \
G(OP_POP) G(OP_POP), \
G(OP_IADD), G(OP_ISUB), G(OP_IMUL), G(OP_IDIV), G(OP_IMOD), G(OP_IPOW), \
G(OP_MOD), G(OP_IUADD), G(OP_IUSUB),
namespace roza namespace roza
{ {

View File

@ -16,8 +16,10 @@ int main(int argc, char** argv)
{ {
std::cerr << "Usage: roza [OPTIONS] <filename>" << std::endl; std::cerr << "Usage: roza [OPTIONS] <filename>" << std::endl;
std::cerr << "Options:" << std::endl; std::cerr << "Options:" << std::endl;
std::cerr << "\t--tokens, show the tokens" << std::endl;
std::cerr << "\t--ast, show the AST" << std::endl; std::cerr << "\t--ast, show the AST" << std::endl;
std::cerr << "\t--code, show the bytecode" << std::endl; std::cerr << "\t--code, show the bytecode" << std::endl;
std::cerr << "\t--stack, show the call stack" << std::endl;
return 0; return 0;
} }
@ -42,10 +44,21 @@ int main(int argc, char** argv)
auto vm = std::make_shared<roza::VM>(log); auto vm = std::make_shared<roza::VM>(log);
lexer->scan(source); lexer->scan(source);
if (args.get("--tokens"))
{
std::cout << "Tokens:" << std::endl;
for (size_t i=0; i<lexer->size(); i++)
{
std::cout << "\t" << lexer->get_or_nullptr(i)->string() << std::endl;
}
}
auto root = parser->parse(); auto root = parser->parse();
if (args.get("--ast")) if (args.get("--ast"))
{ {
std::cout << "AST:" << std::endl;
std::cout << root->string() << std::endl; std::cout << root->string() << std::endl;
} }
@ -54,10 +67,16 @@ int main(int argc, char** argv)
if (args.get("--code")) if (args.get("--code"))
{ {
std::cout << "Bytecode:" << std::endl;
std::cout << prog->string() << std::endl; std::cout << prog->string() << std::endl;
} }
vm->exec(prog); vm->exec(prog);
if (args.get("--stack"))
{
std::cout << vm->string() << std::endl;
}
} }
return 0; return 0;

View File

@ -54,8 +54,7 @@ protected:
TEST_CASE_METHOD(CompilerTest, "Compiler_int") TEST_CASE_METHOD(CompilerTest, "Compiler_int")
{ {
auto prog = get_prog(" 43 "); auto prog = get_prog(" 43 ");
REQUIRE(2 == prog->size()); REQUIRE(1 == prog->size());
test_prog(prog, 0, roza::OP_PUSH_CONST, 0); test_prog(prog, 0, roza::OP_PUSH_CONST, 0);
test_prog(prog, 1, roza::OP_POP);
} }

View File

@ -28,14 +28,30 @@ TEST_CASE_METHOD(LexerTest, "Lexer_integers")
m_lexer.scan("45 12 -3"); m_lexer.scan("45 12 -3");
REQUIRE("INT[45]" == get_str(0)); REQUIRE("INT[45]" == get_str(0));
REQUIRE("INT[12]" == get_str(1)); REQUIRE("INT[12]" == get_str(1));
REQUIRE("INT[-3]" == get_str(2)); REQUIRE("SUB" == get_str(2));
REQUIRE("" == get_str(3)); REQUIRE("INT[3]" == get_str(3));
REQUIRE("" == get_str(4));
} }
TEST_CASE_METHOD(LexerTest, "Lexer_comments") TEST_CASE_METHOD(LexerTest, "Lexer_comments")
{ {
m_lexer.scan("45 # 12 \n -3"); m_lexer.scan("45 # 12 \n -3");
REQUIRE("INT[45]" == get_str(0)); REQUIRE("INT[45]" == get_str(0));
REQUIRE("INT[-3]" == get_str(1)); REQUIRE("SUB" == get_str(1));
REQUIRE("" == get_str(2)); REQUIRE("INT[3]" == get_str(2));
REQUIRE("" == get_str(3));
}
TEST_CASE_METHOD(LexerTest, "Lexer_int_arith")
{
m_lexer.scan("+-*/%^()");
REQUIRE("ADD" == get_str(0));
REQUIRE("SUB" == get_str(1));
REQUIRE("MUL" == get_str(2));
REQUIRE("DIV" == get_str(3));
REQUIRE("MOD" == get_str(4));
REQUIRE("POW" == get_str(5));
REQUIRE("OPAR" == get_str(6));
REQUIRE("CPAR" == get_str(7));
REQUIRE("" == get_str(8));
} }

View File

@ -40,12 +40,33 @@ protected:
TEST_CASE_METHOD(ParserTest, "Parser_integers") TEST_CASE_METHOD(ParserTest, "Parser_integers")
{ {
test_node("PROG", ""); test_node("PROG", "");
test_node("PROG(INSTR(INT[27]))", "27"); test_node("PROG(INT[27])", " 27 ");
test_node("PROG(INSTR(INT[27]))", " 27 "); test_node("PROG(INT[27])", " 27 ");
test_node("PROG(INSTR(INT[27])," test_node("PROG(INT[27],"
"INSTR(INT[9])," "INT[9],"
"INSTR(INT[-99]))", "27 \n 9 \n -99"); "USUB(INT[99]))", "27 \n 9 \n -99");
test_node_err("32 14 -12"); test_node_err("32 14 -12");
} }
TEST_CASE_METHOD(ParserTest, "Parser_int_arith")
{
test_node("PROG(ADD(ADD(INT[1],INT[2]),INT[3]))", "1 + 2 + 3");
test_node("PROG(SUB(SUB(INT[1],INT[2]),INT[3]))", "1 - 2 - 3");
test_node("PROG(ADD(INT[1],MUL(INT[2],INT[3])))", "1 + 2 * 3");
test_node("PROG(MUL(ADD(INT[1],INT[2]),INT[3]))", "(1 + 2) * 3");
test_node("PROG(SUB(INT[1],DIV(INT[2],INT[3])))", "1 - 2 / 3");
test_node("PROG(DIV(SUB(INT[1],INT[2]),INT[3]))", "(1 - 2) / 3");
test_node("PROG(ADD(INT[1],MOD(INT[2],INT[3])))", "1 + 2 % 3");
test_node("PROG(ADD(USUB(INT[2]),INT[3]))", "-2 + 3");
test_node("PROG(ADD(UADD(INT[2]),INT[3]))", "+ 2 + 3");
test_node("PROG(USUB(ADD(INT[2],INT[3])))", " -(2 + 3)");
test_node("PROG(USUB(POW(INT[2],INT[7])))", " -2^7 ");
}