Как стать автором
Обновить

Комментарии 7

Я не буду вдаваться в подробности распределения памяти и способы интерпретации кода, а наоборот, хотелось бы поговорить о самом устройстве компилятора, а именно о лексическом анализаторе и попробовать реализовать его на языке C#.

Об этом было бы еще интересней узнать, поскольку материала по лексическому и синтаксическому анализу в целом больше.


Сама лексема будет в себе хранить ключ, с помощью которого будет определяться принадлежность к типу (служебные слова, операторы, идентификаторы, числа), id лексемы и само значение.

Как понимаю, это иммутабельный класс. Поэтому его поля и свойства должны быть readonly. Ну и в C# принято обозначать локальные переменные без префиксов, а поля — с ними или без:


Скрытый текст
class Lex
{
    public readonly int id;
    public readonly int lex;
    public readonly string val;

    public Lex(int id, int lex, string val)
    {
        this.id = id;
        this.lex = lex;
        this.val = val;
    }
}

private (int, string) SerchLex(string[] lexes)

Во-первых, здесь опечатка: SerchLex -> SearchLex. Во-вторых, обращаю внимание, что метод FindIndex имеет линейную сложность. Так что если лексем будет много, то правильней использовать HashSet или Dictionary, поскольку они имеют константную сложность поиска.


private StringReader sr; // позволяет посимвольно считывать строку

А зачем тут дополнительная обертка, если можно просто по строке итерироваться?
Думаю использование StringReader может снижать производительность.


if (sm[0] == ' ' || sm[0] == '\n' || sm[0] == '\t' || sm[0] == '\0' || sm[0] == '\r' )

В таких случаях нужно выносить одно и то же вычисление в отдельную переменную, т.е. sm0 = sm[0];. Не факт, что компилятор его оптимизирует, ну и код так чище выглядит.


Особое внимание стоит уделить оператору присваивания ":=", который состоит из двух отдельных операторов.

Как вариант, при токенизации можно выбирать лексему с наибольшей длиной, тогда присваивание будет трактоваться именно как отдельный оператор.


Протестировать алгоритм можно по-разному: указать напрямую путь .pas файла, программно создать строку или любой другой удобный вариант. Так как мы пишем на C#, не составит труда добавить форму в приложение, на которой будет 2 textBox-а, первый для ввода кода программы, второй — выводит результат работы алгоритма.

Да можно сразу через консоль тестировать — это на самом деле легче и более
кроссплатформенно. А в идеале — юнит-тесты.


По нажатию кнопки будем запускать анализ текста, а полученный результат будем обрабатывать с помощью switch конструкции: дополнительно выведем к какому типу относится найденная лексема.

Ну этот код уже совсем не годиться — в нем много дублирования, а для соединения строк в цикле используется конкатенация. Первое плохо при исправлении кода, второе — с точки зрения производительности и потребления памяти — конкатенация всегда создает новый объект. Можно переписать этот код следующим образом:


Скрытый текст
private void button1_Click(object sender, EventArgs e)
{
    textBox2.Clear();
    TplMain tpl = new TplMain();
    tpl.Analysis(textBox1.Text);

    var result = new StringBuilder();

    foreach(var lex in tpl.Lexemes)
    {
        string lexName = null;

        switch (lex.id)
        {
            case 1:
                lexName = " служебные слова ";
                break;
            case 2:
                lexName = " ограничители ";
                break;
            case 3:
                lexName = " числа ";
                break;
            case 4:
                lexName = " идентификатор ";
                break;
        }

        if (lexName != null)
        {
            result.Append("id: ");
            result.Append(lex.id);
            result.Append(" lex: ");
            result.Append(lex.lex);
            result.Append(" val: ");
            result.Append(lex.val);
            result.Append(" |");
            result.AppendLine(lexName);
        }
    }

    textBox2.Text = result.ToString();
}

С проектом можно ознакомиться по ссылке

А где ссылка то? :)


Ну и напоследок: почему вы не стали использовать генераторы лексических анализаторов типа ANTLR? Велосипед то — это неплохо, но еще лучше, когда написано почему.

В статье хотел показать примитивное устройство лексического анализатора, с простым функционалом и базовым набором методов, поэтому, думаю, что «велосипед» здесь отчасти оправдан. Со всем остальным полностью согласен, есть что исправить и изменить.
Ну и напоследок: почему вы не стали использовать генераторы лексических анализаторов типа ANTLR?
Я тоже задавался этим вопросом, почему ВСЕ разработчики серьезных компиляторов игнорируют АНТЛР.
Ответ отказался простым.

А в статье идет речь о серьезном компиляторе? И как определяется серьезность? Каким оказался ответ?

В Pascal ":=" — не единственная лексема из нескольких служебных символов. Есть ещё, как минимум, "<>" (не равно), ".." (тип-диапазон), "(*" и "*)" (альтернативный способ задания комментариев).

Лучше сразу предусматривать универсальную обработку лексем из нескольких служебных символов, чем каждый раз отдельно обрабатывать «особый случай».
Паскаль это слишком просто. Вы попробуйте фортран разобрать, где пробелы игнорируются и «F OR» «F O R» тоже самое что «FOR».
«Вот так, с помощью нехитрых приспособлений буханку белого (или черного) хлеба можно превратить в троллейбус… Но зачем?»
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории