Решайте двусмысленность между строками и числами в шутку - PullRequest
0 голосов
/ 26 мая 2020

Я пишу грамматику для формата сериализации, подобного YAML. Я использую парсер LALR. При синтаксическом анализе скаляров я столкнулся с препятствием. Скаляр может быть строкой или числом (давайте оставим его простым и сделаем только десятичными или плавающими). Вот что у меня есть до сих пор, я сохранил только то, что имеет значение здесь:

pair: pair_key ":" _value
_value: scalar | collection

scalar : (string | number) _NL+ 
string : WORD+
number : DECIMAL | FLOAT
DECIMAL : /0|[1-9]\d*/i
FLOAT: /((\d+\.\d*|\.\d+)(e[-+]?\d+)?|\d+(e[-+]?\d+))/i
WORD:  /[^-:#()\[\]{}\n\s]+/

// NEWLINE
_NL: /(\r?\n[\t ]*)+/

%import common.WS_INLINE
%ignore WS_INLINE

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

test_strings = """
a : 28 should be parsed as string
b : 28
"""

Парсер не может выбрать между анализом числа или слова, когда видит 28 в начале.

Вот что Я получаю:

top_map
  pair
    pair_key
      string    a
    scalar
      string
        28
        should
        be
        parsed
        as
        string
  pair
    pair_key
      string    b
    scalar
      string    28

Ожидается:

top_map
  pair
    pair_key
      string    a
    scalar
      string
        28
        should
        be
        parsed
        as
        string
  pair
    pair_key
      string    b
    scalar
      number    28

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

Изменить

Я решил проблему, используя более высокий приоритет в моем числовом правиле как таковом:

string : number WORD+ | WORD+
number.2 : DECIMAL | FLOAT
DECIMAL.2 : /0|[1-9]\d*/i
FLOAT.2: /((\d+\.\d*|\.\d+)(e[-+]?\d+)?|\d+(e[-+]?\d+))/i
WORD:  /[^-:#()\[\]{}\n\s]+/

Таким образом, число будет анализируется как число, а не как СЛОВО. И строки, начинающиеся с цифр, должны иметь СЛОВА, идущие после. Таким образом, в этой модифицированной версии нет строки, которая представляет собой просто число.

1 Ответ

0 голосов
/ 29 мая 2020

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


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

Что-то вроде:

CHAR: /[^-:#()\[\]{}\n]/
CHAR_ND: /[^-:#()\[\]{}\n\d]/
STRING:  CHAR_ND CHAR* | CHAR* CHAR_ND 
...