почерк лексический анализатор

Java Принцип составления
почерк лексический анализатор

предисловие

Мастурбировал большую часть времениPython, который также включает преобразование таблицы базы данных вPythonсерединаORMобрамленныйModel, но мы не нашли подходящего инструмента для этой бессмысленной "ручной работы", поэтому каждый раз, когда мы создаем новую таблицу, каждый пишет ее вручную в соответствии со своей структурой таблицы.Model.

Одна-две таблицы — это хорошо, раз приходится писать больше 10 таблиц, только ты знаешь, что такое боль, на этот раз лозунг программиста еще раз подтвердил, что весь бессмысленный ручной труд со временем будет заменен компьютерами.

intellij plugin

Поскольку готового инструмента нет, напишите его сами, эффект демонстрации следующий:

1-min.gif

Учитывая, что мы в основном используемPyCharmразвитие, простоjetbrainsтакже обеспечиваетSDKдля разработки плагинов, поэтомуUIНет необходимости считать уровень.

Процесс использования очень прост, просто нужно импортироватьDDLзаявление может быть сгенерированоPythonнужныйModelкод.

Например, импортируйте следующий DDL:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userName` varchar(20) DEFAULT NULL COMMENT '用户名',
  `password` varchar(100) DEFAULT NULL COMMENT '密码',
  `roleId` int(11) DEFAULT NULL COMMENT '角色ID',
  PRIMARY KEY (`id`),  
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8

Генерируется соответствующий код Python:

class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    userName = db.Column(db.String)  # 用户名
    password = db.Column(db.String)  # 密码
    roleId = db.Column(db.Integer)  # 角色ID

Лексический анализ

Тщательное сравнение исходного файла и целевого кода позволит легко выяснить правила, не более чем проанализировать имя таблицы, поле и атрибуты поля (будь то первичный ключ, тип, длина) и, наконец, преобразовать это кPythonТребуемый шаблон может быть.

До того, как я начал, я думал, что это очень просто, не более чем разбор строки, но на самом деле я обнаружил, что это не так, в основном это следующие проблемы:

  1. Как определить имя таблицы?
  2. Точно так же, как определить имя поля, но также должны быть связаны тип, длина и комментарий поля.
  3. Как определить первичный ключ?

Подводя итог, можно сказать, что как идентифицировать ключевую информацию в строке с помощью ряда правил, это также то, что делает сервер MySQL.

Прежде чем мы начнем парсить DDL, давайте посмотрим, как парсит следующий простой скрипт:

x = 20

Согласно нашему обычному опыту разработки, это утверждение разделено на следующие части:

  • xпредставляет собой переменную
  • =Указывает обозначение присваивания
  • 20Указывает результат задания

Таким образом, результатом нашего разбора этого скрипта должно быть:

VAR 	 x
GE 	    =
VAL 	 100

Этот процесс синтаксического анализа называется «лексическим синтаксическим анализом» в принципе компиляции, и вы можете слышать его编译原理Эти слова большие (у меня тоже); только что для скрипта мы могли бы написать очень простой лексер для получения такого результата.

переход состояния

Прежде чем начать снова, подумайте об идее, вы можете видеть это в результатах выше, черезVARпредставлять переменные,GEУказывает символ присваивания "=",VALОбозначает результат выполнения задания, и теперь нам нужно сосредоточиться на запоминании этих трех состояний.

При последовательном чтении разбора символов программа переключается между этими состояниями, как показано ниже:

  1. По умолчанию это начальное состояние.
  2. Введите, если символ является буквойVARгосударство.
  3. Введите, когда символ является знаком "="GEгосударство.

Точно так же, когда эти состояния не удовлетворены, он вернется в исходное состояние, чтобы снова подтвердить новое состояние.

Просто смотреть на картинку немного абстрактно, давайте посмотрим непосредственно на основной код:

    public class Result{
        public TokenType tokenType ;
        public StringBuilder text = new StringBuilder();
    }

Во-первых, определяется класс результатов для сбора окончательных результатов синтаксического анализа.TokenTypeЭто соответствует трем состояниям на рисунке, которые просто представлены значениями перечисления.

public enum TokenType {
    INIT,
    VAR,
    GE,
    VAL
}

Первая соответствует первой картинке: состояние инициализации.

Необходимо определить символ для текущего анализируемого символаTokenType:

В соответствии с процессом, описанным на рисунке, достаточно оценить текущий символ и указать состояние.

Тогда это соответствует второй картинке: переходу между состояниями.

войдут разныеcase,в различныхcaseчтобы определить, должен ли он переходить в другие состояния (вводINITсостояние будет восстановлено после состояния).

Например:x = 20:

Предпочтительный войдетVARсостояние, то следующим символом является пробел, естественно повторно входящий в начальное состояние в строке 38, в результате чего следующий символ определяется снова=ВойтиGEгосударство.

когда сценарийab = 30: Первый символ a также является записьюVARсостояние, второй символ b, который по-прежнему является буквой, поэтому введите строку 36, состояние не изменится, и в то же время будет добавлен символ b; последующие шаги такие же, как в предыдущем примере.

Больше говорить бесполезно, предлагаю вам провести одиночный тест самостоятельно и вы поймете:GitHub.com/crossover J я…

DDL-разбор

После завершения простого анализа взглянитеDDLКак следует парсить такой скрипт:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userName` varchar(20) DEFAULT NULL COMMENT '用户名',
  `password` varchar(100) DEFAULT NULL COMMENT '密码',
  `roleId` int(11) DEFAULT NULL COMMENT '角色ID',
  PRIMARY KEY (`id`),  
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8

Принцип аналогичен, во-первых, мы должны увидеть закон (то есть грамматику):

  • Имя таблицы является первой строкой оператора и заканчиваетсяCREATE TABLEначало.
  • Информация о каждом поле (имя, тип, длина, примечание) начинается с символа «`» и заканчивается «,».
  • Первичные ключи — это поля, начинающиеся со строки PRIMART, начиная с)конец.

В соответствии с типом данных, которые нам нужно проанализировать, я определяю это перечисление здесь:

Затем сделайте оценочное назначение при инициализации типа:

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

Рекурсивный разбор

Таргетинг наDDLПравила грамматики, здесь нам все еще нужна специальная обработка, например, как ассоциировать при разборе информации о конкретных полях?

Например:

`userName` varchar(20) DEFAULT NULL COMMENT '用户名',
`password` varchar(100) DEFAULT NULL COMMENT '密码',

Данные, которые мы проанализировали здесь, должны иметь отношение отображения:

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

Итак, здесь я использую рекурсивный способ анализа (не обязательно лучший, каждый может предложить лучшее решение).

} else if (value == '`' && pStatus == Status.BASE_INIT) {
    result.tokenType = DDLTokenType.FI;
    result.text.append(value);
} 

Если текущим символом является символ "`", установите статус в "FI" (FieldInfo) и введите рекурсивную обработку, когда он преобразуется в символ ",".

Можно понять, что этот кусок строки извлекается и обрабатывается отдельно:

`userName` varchar(20) DEFAULT NULL COMMENT '用户名',

Затем рекурсивно вызовите текущий метод, чтобы снова проанализировать этот символ, а затем проанализировать его в соответствии с правилами имени поля, типа, длины и комментария.

В то же время, поскольку есть рекурсия, необходимо связать данные подрекурсии, поэтому я добавил к возвращаемому результату новый.pidполе, это также легко понять.

Значение по умолчанию — 0. После рекурсии оно будет увеличиваться на +1, чтобы гарантировать, что данные каждой рекурсии уникальны.

Используйте тот же метод, чтобы сначала извлечь всю строку при анализе первичного ключа:

PRIMARY KEY (`id`)

Просто "Р" в начале и ")" в конце.

} else if (value == 'P' && pStatus == Status.BASE_INIT) {
    result.tokenType = DDLTokenType.P_K;
    result.text.append(value);
} 

Он также рекурсивно анализирует всю строку и переключает состояние во время рекурсивного процесса.P_K ---> P_K_VНаконец получить первичный ключ.


Итак, сравнив только что абзацDDLРезультаты анализа следующие:

Таким образом, каждое поле также передаетсяpidОбразовались дифференцированные ассоциации.

Так что теперь нам просто нужно инкапсулировать этот лексер, чтобы обеспечить простойAPIчтобы получить данные в таблице.

Суммировать

На данный момент все содержимое всего лексического парсера завершено.Хотя реализация - это небольшая функция, но я сам потратил много времени.Среди них просто рассмотрение принципа компиляции - головная боль.

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

На самом деле, я считаю, что большинство людей думают так же, как и я, это дело слишком низкоуровневое и скучное, и мало кто действительно работает в этой области, так что вы делаете с этим временем?

Так что я тоже решил отказаться от ямы после завершения этого.


Ха-ха, шучу, может быть, я смогу реализовать язык программирования в своей жизни, и у меня будет немного капитала, когда я состарюсь и буду хвастаться своим сыном.

Все адреса исходного кода и плагинов этой статьи:

GitHub.com/crossover J я…

После прочтения не забудьте поставить лайк и поделиться одним щелчком мыши.