示例#1
0
        // инициаизация
        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);
        }
示例#2
0
        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);
        }
示例#3
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";
        }