Как сделать простой подсчет синтаксиса калькулятора для IntelliJ? - PullRequest
0 голосов
/ 16 мая 2019

Я создаю пользовательский плагин поддержки языка в соответствии с этим учебным пособием, и я застрял с несколькими понятиями .bnf.Допустим, я хочу разобрать простой язык калькулятора, который поддерживает +, -, *, /, унарный - и круглые скобки.Вот что у меня сейчас есть:

Flex:

package com.intellij.circom;

import com.intellij.lexer.FlexLexer;
import com.intellij.psi.tree.IElementType;
import com.intellij.circom.psi.CircomTypes;
import com.intellij.psi.TokenType;

%%

%class CircomLexer
%implements FlexLexer
%unicode
%function advance
%type IElementType
%eof{  return;
%eof}

WHITESPACE = [ \n\r\t]+
NUMBER = [0-9]+

%%

{WHITESPACE}    { return TokenType.WHITE_SPACE; }
{NUMBER}        { return CircomTypes.NUMBER; }

Bnf:

{
  parserClass="com.intellij.circom.parser.CircomParser"

  extends="com.intellij.extapi.psi.ASTWrapperPsiElement"

  psiClassPrefix="Circom"
  psiImplClassSuffix="Impl"
  psiPackage="com.intellij.circom.psi"
  psiImplPackage="com.intellij.circom.psi.impl"

  elementTypeHolderClass="com.intellij.circom.psi.CircomTypes"
  elementTypeClass="com.intellij.circom.psi.CircomElementType"
  tokenTypeClass="com.intellij.circom.psi.CircomTokenType"
}

expr ::=
   expr ('+' | '-') expr
  | expr ('*' | '/') expr
  | '-' expr
  | '(' expr ')'
  | literal;
literal ::= NUMBER;

Сначала он жалуется, что expr рекурсивен.Как мне переписать его, чтобы он не был рекурсивным?Во-вторых, когда я пытаюсь скомпилировать и запустить его, он останавливает экземпляр теста идеи при попытке разобрать этот синтаксис, выглядит как бесконечный цикл.

1 Ответ

2 голосов
/ 16 мая 2019

Называть файлы грамматики «BNF» немного вводит в заблуждение, поскольку они на самом деле являются модифицированным форматом PEG (грамматика синтаксического анализа выражения), который допускает некоторые расширенные операторы, включая группирование, повторение и необязательность, и упорядоченный выбор (который семантически отличается от обычное определение |).

Поскольку в основе лежит технология PEG, вы не можете использовать леворекурсивные правила. Левая рекурсия вызовет бесконечный цикл в синтаксическом анализаторе, если генератор кода не откажется генерировать левый рекурсивный код. К счастью, операторы повторения доступны, поэтому вам нужна только рекурсия для синтаксиса с круглыми скобками, и это не левая рекурсия, поэтому она не представляет никаких проблем.

Насколько я вижу из документации, которую я нашел, набор грамматики не предусматривает объявления приоритетов операторов. Если вам действительно нужно произвести правильный анализ с учетом приоритета оператора, вам нужно использовать несколько уровней приоритета. Однако, если ваш единственный вариант использования - подсветка синтаксиса, вам, вероятно, не требуется точно точный анализ, и было бы достаточно сделать что-то вроде следующего:

expr  ::= unary (('+' | '-' | '*' | '/') unary)*
unary ::= '-'* ( '(' expr ')' | literal )

(Для точного разбора вам нужно разделить expr выше на два уровня приоритета, один для аддитивных операторов и другой для мультипликативного. Но я не советую этого делать, если вы не собираетесь использовать синтаксический анализ для оценки или кодирования. поколение.) * * 1 010

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

...