Files
pzks-labs/src/parser.cpp
T

426 lines
7.3 KiB
C++
Raw Normal View History

2026-10-02 20:31:24 +03:00
#include "expression.hpp"
#include "print.h"
2026-10-07 10:09:05 +03:00
#include <cctype>
#include <cstring>
#include <iostream>
#include <vector>
2026-10-02 20:31:24 +03:00
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
{
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
return cumulative_backtrack;
2026-10-02 20:31:24 +03:00
}
public:
char buffer[256];
2026-10-05 11:17:48 +03:00
std::vector<Expression::Token>& pv;
2026-10-02 20:31:24 +03:00
2026-10-05 11:17:48 +03:00
Parser(std::vector<Expression::Token>& pv)
2026-10-02 20:31:24 +03:00
: s(I), pv(pv)
{
buf_clear();
}
void buf_clear(void)
{
2026-10-04 14:13:14 +03:00
memset(buffer, 0, MAX_TOKEN_STRING_LEN);
2026-10-02 20:31:24 +03:00
}
void buf_push(char c)
{
2026-10-04 14:13:14 +03:00
if (int i = strlen(buffer); i < MAX_TOKEN_STRING_LEN - 1) {
buffer[i] = c;
}
2026-10-02 20:31:24 +03:00
}
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-04 14:13:14 +03:00
// as per requirements (report all wrong symbols)
if (c != ' ' && c != '\0')
{
pr_warn("Unrecognized character: " << c);
}
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
{
2026-10-04 14:13:14 +03:00
// additional check as per requirements
{
int i, c;
#if (MAX_TOKEN_STRING_LEN % 8) == 0
for (i = 0, c = 0; i < MAX_TOKEN_STRING_LEN; i += 8)
{
c += (buffer[i+0] == '.')
+ (buffer[i+1] == '.')
+ (buffer[i+2] == '.')
+ (buffer[i+3] == '.')
+ (buffer[i+4] == '.')
+ (buffer[i+5] == '.')
+ (buffer[i+6] == '.')
+ (buffer[i+7] == '.');
}
#else
for (int i = 0, c = 0; i < MAX_TOKEN_STRING_LEN; i++)
{
c += buffer[i] == '.';
}
#endif
if (c > 1)
{
pr_warn("Too many dots in CONST: " << buffer);
return 0;
}
}
2026-10-02 20:31:24 +03:00
double value;
if (!sscanf(buffer, "%lf", &value))
{
pr_warn("Invalid CONST: " << buffer);
}
else
{
2026-10-05 11:17:48 +03:00
pv.push_back(Expression::Token(value));
2026-10-02 20:31:24 +03:00
}
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
{
2026-10-05 11:17:48 +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, "("))
{
2026-10-05 11:17:48 +03:00
pv.push_back(Expression::Token(Expression::Token::OPA));
2026-10-02 22:14:03 +03:00
break;
}
else if (!strcmp(buffer, ")"))
{
2026-10-05 11:17:48 +03:00
pv.push_back(Expression::Token(Expression::Token::CPA));
2026-10-02 22:14:03 +03:00
break;
}
else if (!strcmp(buffer, "+"))
{
2026-10-05 11:17:48 +03:00
pv.push_back(Expression::Token(Expression::Token::ADD));
2026-10-02 22:14:03 +03:00
break;
}
else if (!strcmp(buffer, "-"))
{
2026-10-05 11:17:48 +03:00
pv.push_back(Expression::Token(Expression::Token::SUB));
2026-10-02 22:14:03 +03:00
break;
}
else if (!strcmp(buffer, "*"))
{
2026-10-05 11:17:48 +03:00
pv.push_back(Expression::Token(Expression::Token::MUL));
2026-10-02 22:14:03 +03:00
break;
}
else if (!strcmp(buffer, "/"))
{
2026-10-05 11:17:48 +03:00
pv.push_back(Expression::Token(Expression::Token::DIV));
2026-10-02 22:14:03 +03:00
break;
}
else if (!strcmp(buffer, "**"))
{
2026-10-05 11:17:48 +03:00
pv.push_back(Expression::Token(Expression::Token::POW));
2026-10-02 22:14:03 +03:00
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-05 11:17:48 +03:00
std::vector<Expression::Token> tokenize_input(const char * const input_string)
2026-10-02 20:31:24 +03:00
{
2026-10-05 11:17:48 +03:00
std::vector<Expression::Token> pv;
2026-10-02 20:31:24 +03:00
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;
2026-10-05 11:17:48 +03:00
default:
pr_warn("Token skipped");
break;
2026-10-02 20:31:24 +03:00
}
}
2026-10-05 11:17:48 +03:00
2026-10-02 20:31:24 +03:00
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() << ") ";
}
2026-10-07 18:11:39 +03:00
if (tv.size())
{
std::cout << "(" << *tv[i].to_str() << ")\n";
}
2026-10-02 22:14:03 +03:00
}
void print_math_vector(const std::vector<Expression::Token>& tv)
{
int i, l;
for (i = 0, l = tv.size() - 1; i < l; i++)
{
2026-10-05 21:11:17 +03:00
std::cout << *tv[i].to_math_str(); //<< " ";
}
2026-10-07 18:11:39 +03:00
if (tv.size())
{
std::cout << *tv[i].to_math_str() << "\n";
}
}
void print_math_vector(const std::vector<Expression::Token>& tv, const std::vector<int>& highlight_locations)
{
int i, l, h, hl;
for (i = 0, l = tv.size() - 1, h = 0, hl = highlight_locations.size(); i < l; i++)
{
if (h < hl && highlight_locations[h] == i)
{
std::cout << "\033[31m" << *tv[i].to_math_str() << "\033[0m";
h++;
}
else
{
std::cout << *tv[i].to_math_str();;
}
}
if (tv.size())
{
2026-10-15 16:42:52 +03:00
if (highlight_locations[highlight_locations.size()-1] == (long) (tv.size() - 1))
{
std::cout << "\033[31m" << *tv[tv.size() - 1].to_math_str() << "\033[0m\n";
}
else
{
std::cout << *tv[tv.size() - 1].to_math_str() << "\n";
}
}
}
2026-10-02 20:31:24 +03:00
}