Ветвление на рычаге парсера в зависимости от содержимого токена

Я работаю над простым анализатором / лексером для небольшого проекта, но столкнулся с проблемой.

Я разбираю контент по этим строкам:

Name SEP Gender SEP Birthday
Name SEP Gender SEP Birthday

… Где SEP - любое (но не кратное!) Из |, , или пробелов.

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

%token <string> SEP
%token <string> VAL
%token NL

%token EOF

Теперь я должен выдать ошибку синтаксического анализа, если, например, поле gender не содержит небольшого набора определенных значений, скажем {male,female,neither,unspecified}. Я могу обернуть синтаксический анализатор и разобраться с этим, но мне бы очень хотелось закодировать это требование в автомате для будущего расширения.

Моя первая попытка, выглядевшая примерно так, ужасно провалилась:

doc:
   | EOF              { [] }
   | it = rev_records { it }
   ;

rev_records:
           | (* base-case: empty *) { [] }
           | rest = rev_records; record; NL  { record :: rest }
           | rest = rev_records; record; EOF { record :: rest }
           ;

record:
   last_name = name_field; SEP; first_name = name_field; SEP;
   gender = gender_field; SEP; favourite_colour = colour_field; SEP;
   birthday = date_field
   { {last_name; first_name; gender; favourite_colour; birthday} }

name_field: str = VAL { str }

gender_field:
            | VAL "male" { Person.Male }
            | VAL "female" { Person.Female }
            | VAL "neither" { Person.Neither }
            | VAL "unspecified" { Person.Unspecified }
            ;

Да, без кубиков. Очевидно, моя попытка неструктурированного лексирования уже терпит неудачу.

Какой идиоматический способ разобрать что-то вроде этого?


person ELLIOTTCABLE    schedule 16.07.2018    source источник
comment
Я не эксперт в синтаксических анализаторах, но я бы токенизировал принятые значения, поскольку они имеют синтаксическое значение, а затем определил gender_field как объединение этих токенов.   -  person Richard-Degenne    schedule 18.07.2018


Ответы (1)


Синтаксические анализаторы, такие как Menhir и OCamlYacc, работают с токенами, а не со строками или символами. Преобразование символов в токены выполняется на уровне лексера. Вот почему вы не можете указать строку в производственном правиле.

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

record:
   last_name = name_field; SEP; first_name = name_field; SEP;
   gender_val = VAL; SEP; favourite_colour = colour_field; SEP;
   birthday = date_field
   { 
     let gender = match gender_val with
     | "male" -> Person.Male
     | "female" -> Person.Female
     | "neither" -> Person.Neither
     | "unspecified" -> Person.Unspecified
     | _ -> failwith "Parser error: invalid value in the gender field" in
      {last_name; first_name; gender; favourite_colour; birthday}   
    }

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

rule token = parser
| "male" | "female" | "neither" | "unspecified" as -> {GENDER s}
...

Однако это не рекомендуется, так как это фактически превратит male, female и т. Д. В ключевые слова, поэтому их появление в других местах нарушит вашу грамматику.

person ivg    schedule 19.07.2018
comment
Возможно, вам стоит добавить конструкторы, такие как Person.Male, которые используются в вопросе. - person PatJ; 19.07.2018
comment
Кроме того, обработка пола во время лексирования не так уж идеальна, эти слова могут появиться где-то в другом месте и сломать материал. - person PatJ; 19.07.2018
comment
да, это хороший момент. Это в основном делает указанные гендерные ключевые слова. Так что это не должно быть ошибкой парсера. - person ivg; 19.07.2018