Как реализовать лексический анализ в Javascript
Привет, ребята, спасибо за чтение
В настоящее время я пытаюсь выполнить калькулятор в стиле Google. Вы вводите строку, она определяет, можно ли ее вычислить и возвращает результат.
Я начал медленно с основ: + - / *
и обработка скобок.
Я готов улучшить калькулятор с течением времени, и немного узнав о лексическом анализе, я создал список токенов и связанных шаблонов регулярных выражений.
Этот вид работы легко применим к языкам, таким как Lex и Yacc, за исключением того, что я разрабатываю только Javascript-приложение.
Я попытался транскрибировать идею в Javascript, но я не могу понять, как обрабатывать все в чистом и красивом виде, особенно вложенные круглые скобки.
Анализ
Определите, что такое запрос калькулятора:
// NON TERMINAL EXPRESSIONS //
query -> statement
query -> ε // means end of query
statement -> statement operator statement
statement -> ( statement )
statement -> prefix statement
statement -> number
number -> integer
number -> float
// TERMINAL EXPRESSIONS //
operator -> [+*/%^-]
prefix -> -
integer -> [0-9]+
float -> [0-9]+[.,][0-9]+
Javascript
Лексический анализ состоит в проверке, что нет ничего, что не похоже на одно из терминальных выражений: operator, prefixes, integer и float. Который может быть сокращен до одного регулярного выражения:
(Я добавил пробелы, чтобы сделать его более читаемым)
var calcPat =
/^ (\s*
( ([+/*%^-]) | ([0-9]+) | ([0-9]+[.,][0-9]+) | (\() | (\)) )
)+ \s* $/;
Если этот тест проходит, запрос лексически корректен и должен быть проверен грамматикой, чтобы определить, можно ли его вычислить. Это сложная часть
Я не собираюсь вставлять код, потому что он не чист и не понятен, но я собираюсь объяснить процесс, за которым я последовал, и почему я застрял:
Я создал метод под названием isStatement(string)
, который должен был называть себя рекурсивно. Основная идея состоит в том, чтобы разбить строку на "потенциальные" операторы и проверить, действительно ли они являются утверждениями и образуют их вообще.
Процесс следующий:
-Если первые два токена представляют собой число, за которым следует оператор:
-Тогда,
- Если остальное - всего лишь один токен, и это число:
--- Тогда это утверждение.
--- Else, проверьте, если остальные токены образуют оператор (рекурсивный вызов)
-Else, если первый токен - это скобка
-Тогда найдите подходящую закрывающую скобку и проверьте, что внутри внутри есть оператор (рекурсия)
- Также проверьте, есть ли что-то после закрытия скобки, и если оно формирует оператор, связанный со структурой скобок.
В чем проблема?
Моя проблема в том, что я не могу найти соответствующие скобки, когда есть вложенные структуры. Как я могу это сделать? Также, как вы можете видеть, это не особый общий и чистый алгоритм проверки грамматики. У вас есть идея улучшить этот шаблон?
Большое вам спасибо за то, что потратили время на все.
Гаэль
(PS: Как вы, наверное, заметили, я не являюсь носителем английского языка! Извините за ошибки и все!)
Ответы
Ответ 1
У вас есть правильная идея о том, что такое лексический анализ, но вы, похоже, путаетесь в различии между грамматикой и грамматикой языка. Это две разные вещи.
-
Глоссарий-маркер - это набор шаблонов (обычно регулярных выражений), которые описывают токены для языка, который будет разбираться. Регулярными выражениями являются выражения над набором символов.
-
Языковая грамматика (или целевая грамматика, я полагаю) является грамматикой для языка, который вы хотите проанализировать. Эта грамматика выражается в терминах токенов.
Вы не можете написать регулярное выражение для анализа алгебраических обозначений. Вы просто не можете. Вы можете написать для нее грамматику, но это не обычная грамматика. То, что вы хотите сделать, - это распознать отдельные токены, которые в вашем случае могут быть выполнены с регулярным выражением, как будто у вас есть. Фокус в том, что вы не применяете это выражение для общего предложения, которое нужно проанализировать. Вместо этого вы хотите сопоставить токен в текущей точке предложения.
Теперь, поскольку у вас есть регулярные выражения Javascript для работы, вы можете найти регулярное выражение, предназначенное для соответствия строкам токенов. Трюк с этим будет придумать способ определить, какой токен был выбран из списка возможностей. Ядро JavaScript-регенератора может вернуть вам массивы групп, поэтому, возможно, вы могли бы создать что-то поверх этого.
edit — Я пытаюсь понять, как вы могли бы собрать (несколько) универсальный маркер-маркер, начиная с списка отдельных регулярных выражений (по одному для каждого токена). Возможно, это не очень сложно, и было бы неплохо иметь вокруг.