// инициаизация static void init(ref RegularGenerator gen) { token_descs.Clear(); gen.get_root().A = 1; token_description tmp; tmp.name = "t_none"; tmp.expr = ""; tmp.type = token_t.sysyem; token_descs.Add(tmp); }
static public int Gen(String src, out String header, out String body, String UnitName) { RegularGenerator gen = new RegularGenerator(); String tmp = ""; bool first = true; StringBuilder ss = new StringBuilder(); foreach (char ch in UnitName) { if ('a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || '0' <= ch && ch <= '9' || ch == '_') { if (first && '0' <= ch && ch <= '9') { ss.Append('_', 1); } ss.Append(ch); } if (ch == ' ') { ss.Append('_'); } first = false; } if (ss.Length == 0) { UnitName = "untitled"; } else { UnitName = ss.ToString(); } init(ref gen); int i = 0; int j; int line = 1; int line_begin = -1; bool mute_expr = false; // обработка while (i < src.Length) { // ищем начало for (; i < src.Length && RegularGenerator.ws(src[i]); i++) { if (src[i] == '\n') { // просто начало строки (вместо разделения точкой с запятой) process_token(token_t.eol, "\n"); mute_expr = false; line++; line_begin = i; } } if (i == src.Length) { break; } j = i; switch (src[i]) { case '#': // комментарий for (i++; i < src.Length && src[i] != '\n'; i++) { ; } continue; // начало выражения case '(': { if (mute_expr) { break; } // начало выражения потом его в собственный компилятор загоним int brack = 1; bool screen = false; for (i++; i < src.Length && brack > 0 && src[i] != '\n'; i++) { if (screen) { // экранироване действует лишь на один символ // что конкретно экранируется сейчас не особо важно screen = false; } else { // не экранированные символы участвуют в подсчете if (src[i] == '(') { brack++; } else if (src[i] == ')') { brack--; } else if (src[i] == '\\') { screen = true; } } } tmp = src.Substring(j, i - j); // очищаем от внешних скобок они больше не нужны if (brack > 1) { // где-то в выражении есть незакрытые скобки ErrStr += $"[ERROR] unbalanced brackets at {line}:{j - line_begin}"; header = ""; body = ""; return(-1); } else if (brack == 1) { // одну скобку мы можем закрыть, так как точно знаем что это за скобка // (с неё начинается любое регулярное выражение) ErrStr += $"[WARNING] expression not closed at {line}:{j - line_begin}"; } else { tmp = tmp.Remove(tmp.Length - 1); } tmp = tmp.Remove(0, 1); // отправляем на дальнейшую обработку try { process_token(token_t.expr, tmp); } catch (Exception e) { ErrStr += $"[ERROR] {e.Message} \"{tmp}\" at {line}:{i - line_begin - tmp.Length}"; header = ""; body = ""; return(-1); } continue; } } // найдем идентификатор for (; i < src.Length && !RegularGenerator.ws(src[i]); i++) { ; } tmp = src.Substring(j, i - j); // уточним найденный идентификатор (ключевое слово/идентификатор) token_t token = recognize(tmp); // отправка на обраотку try { process_token(token, tmp); } catch (Exception e) { ErrStr += $"[ERROR] {e.Message} \"{tmp}\" at {line}:{i - line_begin - tmp.Length}"; header = ""; body = ""; return(-1); } } process_token(token_t.eof, tmp); // Компиляция включаемых файлов token_descs.Sort(ItemCmp); Int32 id = 0; foreach (token_description item in token_descs) { try { // добавить ветвь в дерево состояний if (item.type != token_t.sysyem) { if (item.type == token_t.mute) { gen.add_branch(item.expr, 0); } else { gen.add_branch(item.expr, id); } } id++; } catch (EIndeterminate e) { ErrStr = $"[ERROR] {e.Message} \"{tmp}\" at {line}:{i - line_begin - tmp.Length}"; header = ""; body = ""; return(-1); } catch (Exception e) { ErrStr = $"[ERROR] {e.Message}"; header = ""; body = ""; return(-1); } } // Заголовочный файл write_header(out header, UnitName); // Конеченный автомат и вспомогательные функци write_source_file(out body, UnitName, ref gen); return(0); }
static void write_source_file(out String output, String UnitName, ref RegularGenerator gen) { // Шапка файла output = $"// Auto generated file by LexGen program ver: {PROGRAM_VERSION}\n" + "// Please don't edit manually\n" + "#include <string.h>\n" + "#include <stdlib.h>\n" + $"#include \"{UnitName}.h\"\n" + "\n" + // Вспомогателные функции "size_t tokens_length = 0;\n" + "size_t tokens_capacity = 0;\n" + "selection_t *token_str = NULL;\n" + "token_t *tokens = NULL;\n" + "\n" + "void push_token(token_t token, size_t begin, size_t end) {\n" + "\tif (tokens_length == tokens_capacity) {\n" + "\t\ttokens_capacity += 32;\n" + "\t\ttokens = (token_t*)realloc(tokens, tokens_capacity * sizeof(tokens[0]));\n" + "\t\ttoken_str = (selection_t*)realloc(token_str, tokens_capacity * sizeof(token_str[0]));\n" + "\t}\n" + "\ttokens[tokens_length] = token;\n" + "\ttoken_str[tokens_length].begin = begin;\n" + "\ttoken_str[tokens_length].end = end;\n" + "\ttokens_length++;\n" + "}\n" + "\n" + "token_t pop_token() {\n" + "\ttokens_length--;\n" + "\treturn tokens[tokens_length];\n" + "}\n" + "\n" + "selection_t get_token_str() {\n" + "\treturn token_str[tokens_length];\n" + "}\n" + "\n" + "bool ws(char ch) {\n" + "\treturn ch == ' ' || ch == '\\f' ||\n" + "\t\tch == '\\t' || ch == '\\v' || ch == '\\n' || ch == '\\r';\n" + "}\n" + "\n" + "bool digit(char ch) {\n" + "\treturn '0' <= ch && ch <= '9';\n" + "}\n" + "\n" + "bool word(char ch) {\n" + "\treturn 'a' <= ch && ch <= 'z' ||\n" + "\t\t'A' <= ch && ch <= 'Z' ||\n" + "\t\t'0' <= ch && ch <= '9' ||\n" + "\t\tch == '_';\n" + "}\n" + "\n" + "// Save current state\n" + "void push_state(states_t *states, unsigned state, unsigned substate) {\n" + "\tif (states->length == states->capacity) {\n" + "\t\tstates->capacity += 32;\n" + "\t\tstates->state = (unsigned*)realloc(\n" + "\t\t\tstates->state, sizeof(states->state[0]) * states->capacity);\n" + "\t\tstates->substate = (unsigned*)realloc(\n" + "\t\t\tstates->substate, sizeof(states->substate[0]) * states->capacity);\n" + "\t}\n" + "\tstates->state[states->length] = state;\n" + "\tstates->substate[states->length] = substate;\n" + "\tstates->length++;\n" + "}\n" + "\n" + "// Load state\n" + "void pop_state(states_t *states, unsigned *state, unsigned *substate) {\n" + "\tif (states->length > 0) {\n" + "\t\tstates->length--;\n" + "\t\t*state = states->state[states->length];\n" + "\t\t*substate = states->substate[states->length] + 1;\n" + "\t}\n" + "\telse {\n" + "\t\t*state = 0;\n" + "\t\t*substate = 0;\n" + "\t}\n" + "}\n\n"; // запись конечного автомата write_state_machine(ref output, ref gen.elements); // Функция для преобразования токена в текстовую форму output += "\n" + "char* token_to_string(token_t token){\n" + "\tswitch(token) {"; foreach (token_description t in token_descs) { output += $"\tcase {t.name}: return \"{t.name}\";\n"; } output += "\t}\n" + "\treturn NULL;\n" + "}\n\n"; }