include iostream include cctype include parser using namespace std nam

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <iostream>
#include <cctype>
#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;
}
}