#include #include #include "parser.h" using namespace std; namespace parser { // Теги лексем enum tag_t { IDENT, NUMBER, LPAREN, RPAREN, IF, LBRACE, RBRACE, SEMICOLON, EQUAL, END , EPSILON }; //___________0______1_______2_______3_______4___5_______6_______7__________8______9___,10_______ // Контекст парсера struct context { std::string text; // текст для анализа coord cur; // координаты текущей позиции в тексте coord next; // координаты следующей позиции в тексте coord start; // координаты начала текущей лексемы tag_t tag; // тег текущей лексемы }; // next_char считывает следующий символ из текста и возвращает его код. // Если достигнут конец текста, next_char возвращает -1. int next_char(context& ctx) { ctx.cur = ctx.next; if (ctx.next.offs == ctx.text.length()) return -1; char c = ctx.text[ctx.next.offs++]; if (c == '\n') { ctx.next.line++; ctx.next.col = 1; } else { ctx.next.col++; } return c; } // next_token распознаёт следующую лексему в тексте. void next_token(context& ctx) throw(coord) { int c; while (isspace(c = next_char(ctx))); ctx.start = ctx.cur; switch (c) { case -1: ctx.tag = END; break; case '(': ctx.tag = LPAREN; break; case ')': ctx.tag = RPAREN; break; case '{': ctx.tag = LBRACE; break; case '}': ctx.tag = RBRACE; break; case ';': ctx.tag = SEMICOLON; break; case '=': ctx.tag = EQUAL; break; default: if (isalpha(c)) { if (c == 'i' && next_char(ctx) == 'f') { ctx.tag = IF; // cout << ctx.next.col << endl; break; } else while (isalnum(c = next_char(ctx))); ctx.next.col-=1; ctx.next.offs-=1; ctx.tag = IDENT; } else if (isdigit(c)) { while (isdigit(c = next_char(ctx))); ctx.next.col-=1; ctx.next.offs-=1; ctx.tag = NUMBER; } else { throw ctx.cur; } } } void parse_stmt(context&) throw(coord); void parse_seq(context&) throw(coord); void parse(std::string text) throw(coord) { context ctx { text }; ctx.next = coord{ 0, 1, 1 }; next_token(ctx); parse_stmt(ctx); // next_token(ctx); if (ctx.tag != END) throw ctx.start; } void parse_stmt(context& ctx) throw(coord) { switch (ctx.tag) { case IF: next_token(ctx); if (ctx.tag != LPAREN) throw ctx.start; next_token(ctx); if (ctx.tag != IDENT) throw ctx.start; next_token(ctx); if (ctx.tag != RPAREN) throw ctx.start; else { next_token(ctx); parse_stmt(ctx); break; } case IDENT: next_token(ctx); if (ctx.tag != EQUAL) throw ctx.start; next_token(ctx); if (ctx.tag != NUMBER) throw ctx.start; next_token(ctx); if (ctx.tag != SEMICOLON) throw ctx.start; break; case LBRACE: next_token(ctx); parse_seq(ctx); // if (ctx.tag != RBRACE) throw ctx.start; next_token(ctx); break; default : throw ctx.start; } } void parse_seq(context& ctx) throw(coord) { if (ctx.tag != RBRACE) { parse_stmt(ctx); if (ctx.tag == RBRACE) return; if (ctx.tag != IDENT) next_token(ctx); parse_seq(ctx); } else return; } }