Files
pzks-labs/src/parser.cpp
T

346 lines
5.9 KiB
C++
Raw Normal View History

2026-10-02 20:31:24 +03:00
#include <iostream>
#include <cctype>
#include <cstring>
#include <memory>
#include <vector>
#include "expression.hpp"
#include "print.h"
namespace Parser {
class Parser
{
enum State {
I, // idle
RC, // read constant
RV, // read variable
OP, // read operator
} s;
const char *state_str(enum State e)
{
switch (e)
{
case I:
return "I";
case RC:
return "RC";
case RV:
return "RV";
case OP:
return "OP";
default:
return "Not a valid state!";
}
}
2026-10-02 22:14:03 +03:00
int switch_state(enum State e)
2026-10-02 20:31:24 +03:00
{
pr_debug("Leaving " << state_str(s) << ", entering " << state_str(e));
2026-10-02 22:14:03 +03:00
int cumulative_backtrack = 0;
2026-10-02 20:31:24 +03:00
switch (s)
{
case I:
2026-10-02 22:14:03 +03:00
cumulative_backtrack += leave_i();
2026-10-02 20:31:24 +03:00
break;
case RC:
2026-10-02 22:14:03 +03:00
cumulative_backtrack += leave_rc();
2026-10-02 20:31:24 +03:00
break;
case RV:
2026-10-02 22:14:03 +03:00
cumulative_backtrack += leave_rv();
2026-10-02 20:31:24 +03:00
break;
case OP:
2026-10-02 22:14:03 +03:00
cumulative_backtrack += leave_op();
2026-10-02 20:31:24 +03:00
break;
default:
pr_warn("Warning: broken state machine on leave");
break;
}
switch (e)
{
case I:
enter_i();
break;
case RC:
enter_rc();
break;
case RV:
enter_rv();
break;
case OP:
enter_op();
break;
default:
pr_warn("Warning: broken state machine on enter");
break;
}
s = e;
2026-10-02 22:14:03 +03:00
pr_debug("Cumulative backtrack is " << cumulative_backtrack);
return cumulative_backtrack;
2026-10-02 20:31:24 +03:00
}
public:
char buffer[256];
std::shared_ptr<std::vector<Expression::Token>>& pv;
Parser(std::shared_ptr<std::vector<Expression::Token>>& pv)
: s(I), pv(pv)
{
buf_clear();
}
void buf_clear(void)
{
memset(buffer, 0, 256);
}
void buf_push(char c)
{
buffer[strlen(buffer)] = c;
}
int dispatch_to_current(char c)
{
switch (s)
{
case I:
return parse_i(c);
case RC:
return parse_rc(c);
case RV:
return parse_rv(c);
case OP:
return parse_op(c);
default:
pr_warn("State machine is broken, unable to dispatch character " << c << ", returning 0");
return 0;
}
}
void enter_i(void) {}
int parse_i(char c)
{
if (isdigit(c) || c == '.')
{
2026-10-02 22:14:03 +03:00
return switch_state(RC) + 1;
2026-10-02 20:31:24 +03:00
}
else if (isalpha(c))
{
2026-10-02 22:14:03 +03:00
return switch_state(RV) + 1;
2026-10-02 20:31:24 +03:00
}
else if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')')
{
2026-10-02 22:14:03 +03:00
return switch_state(OP) + 1;
2026-10-02 20:31:24 +03:00
}
else
{
2026-10-02 22:14:03 +03:00
pr_debug("Unknown character skipped (" << c << "), still in idle");
2026-10-02 20:31:24 +03:00
return 0;
}
}
2026-10-02 22:14:03 +03:00
int leave_i(void)
{
return 0;
}
2026-10-02 20:31:24 +03:00
void enter_rc(void)
{
buf_clear();
}
int parse_rc(char c)
{
if (!(isdigit(c) || c == '.'))
{
2026-10-02 22:14:03 +03:00
return switch_state(I) + 1;
2026-10-02 20:31:24 +03:00
}
else
{
buf_push(c);
return 0;
}
}
2026-10-02 22:14:03 +03:00
int leave_rc(void)
2026-10-02 20:31:24 +03:00
{
double value;
if (!sscanf(buffer, "%lf", &value))
{
pr_warn("Invalid CONST: " << buffer);
}
else
{
pv->push_back(Expression::Token(value));
}
2026-10-02 22:14:03 +03:00
return 0;
2026-10-02 20:31:24 +03:00
}
void enter_rv(void)
{
buf_clear();
}
int parse_rv(char c)
{
if (!isalpha(c))
{
2026-10-02 22:14:03 +03:00
return switch_state(I) + 1;
2026-10-02 20:31:24 +03:00
}
else
{
buf_push(c);
return 0;
}
}
2026-10-02 22:14:03 +03:00
int leave_rv(void)
2026-10-02 20:31:24 +03:00
{
pv->push_back(Expression::Token(buffer));
2026-10-02 22:14:03 +03:00
return 0;
2026-10-02 20:31:24 +03:00
}
void enter_op(void)
{
buf_clear();
}
int parse_op(char c)
{
if (!(c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')'))
{
2026-10-02 22:14:03 +03:00
return switch_state(I) + 1;
2026-10-02 20:31:24 +03:00
}
else
{
buf_push(c);
return 0;
}
}
2026-10-02 22:14:03 +03:00
int leave_op(void)
2026-10-02 20:31:24 +03:00
{
2026-10-02 22:14:03 +03:00
int i, downsize;
for (i = strlen(buffer), downsize = 0; i > 0; buffer[--i] = '\0', downsize++)
2026-10-02 20:31:24 +03:00
{
2026-10-02 22:14:03 +03:00
if (!strcmp(buffer, "("))
{
pv->push_back(Expression::Token(Expression::Token::OPA));
break;
}
else if (!strcmp(buffer, ")"))
{
pv->push_back(Expression::Token(Expression::Token::CPA));
break;
}
else if (!strcmp(buffer, "+"))
{
pv->push_back(Expression::Token(Expression::Token::ADD));
break;
}
else if (!strcmp(buffer, "-"))
{
pv->push_back(Expression::Token(Expression::Token::SUB));
break;
}
else if (!strcmp(buffer, "*"))
{
pv->push_back(Expression::Token(Expression::Token::MUL));
break;
}
else if (!strcmp(buffer, "/"))
{
pv->push_back(Expression::Token(Expression::Token::DIV));
break;
}
else if (!strcmp(buffer, "**"))
{
pv->push_back(Expression::Token(Expression::Token::POW));
break;
}
2026-10-02 20:31:24 +03:00
}
2026-10-02 22:14:03 +03:00
if (i)
2026-10-02 20:31:24 +03:00
{
2026-10-02 22:14:03 +03:00
return downsize;
2026-10-02 20:31:24 +03:00
}
else
{
pr_warn("Skip unknown operator: " << buffer);
2026-10-02 22:14:03 +03:00
return 0;
2026-10-02 20:31:24 +03:00
}
}
};
2026-10-02 22:14:03 +03:00
std::shared_ptr<std::vector<Expression::Token>> tokenize_input(const char * const input_string)
2026-10-02 20:31:24 +03:00
{
std::shared_ptr<std::vector<Expression::Token>> pv = std::make_shared<std::vector<Expression::Token>>();
Parser p(pv);
2026-10-02 22:14:03 +03:00
for (int i = 0, l = strlen(input_string) + 1; i < l; i++)
2026-10-02 20:31:24 +03:00
{
i -= p.dispatch_to_current(input_string[i]);
}
return pv;
}
2026-10-02 22:14:03 +03:00
int assert_same(const std::vector<Expression::Token>& a, const std::vector<Expression::Token>& b)
2026-10-02 20:31:24 +03:00
{
if (a.size() != b.size())
{
std::cout << "Vectors are of different lengths: " << a.size() << " != " << b.size() << "\n";
return 1;
}
for (int i = 0, l = a.size(); i < l; i++)
{
if (a[i].t != b[i].t)
{
std::cout << "Token " << i << " types differ: " << a[i].type_str() << " != " << b[i].type_str() << "\n";
return 1;
}
switch (a[i].t)
{
case Expression::Token::VAR:
if (strcmp((*(a[i].v.s)).c_str(),
(*(b[i].v.s)).c_str()))
{
std::cout << "Variable names at " << i << " differ: " << (*(a[i].v.s)).c_str() << " != " << (*(b[i].v.s)).c_str() << "\n";
return 1;
}
break;
case Expression::Token::CONST:
if (a[i].v.d != b[i].v.d)
{
std::cout << "Constants at " << i << " differ: " << a[i].v.d << " != " << b[i].v.d << "\n";
return 1;
}
break;
case Expression::Token::OPERATOR:
if (a[i].v.o != b[i].v.o)
{
std::cout << "Operators at " << i << " differ: " << a[i].op_str() << " != " << b[i].op_str() << "\n";
return 1;
}
break;
}
}
return 0;
}
2026-10-02 22:14:03 +03:00
void print_token_vector(const std::vector<Expression::Token>& tv)
{
int i, l;
for (i = 0, l = tv.size() - 1; i < l; i++)
{
std::cout << "(" << *tv[i].to_str() << ") ";
}
std::cout << "(" << *tv[i].to_str() << ")\n";
}
2026-10-02 20:31:24 +03:00
}