Парсинг грамматик с помощью OCaml

Нет, но можно создать и использовать новый mkspec, я думаю, что qmake также определяет идентификатор платформы, названный в честь текущего mkspec. Почему необходимо протестировать на 64 бита?

Reed

10
задан Gilles 'SO- stop being evil' 16 September 2012 в 21:19
поделиться

3 ответа

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

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

type expr =
    | Operation of term * binop * term
    | Term of term
and term =
    | Num of num
    | Lvalue of expr
    | Incrop of incrop * expression
and incrop = Incr | Decr
and binop = Plus | Minus
and num = int

Тогда я бы реализовал парсер рекурсивного спуска. Конечно, было бы намного лучше, если бы вы могли использовать потоки в сочетании с препроцессором camlp4of ...

Кстати, в документации OCaml есть небольшой пример арифметических выражений. здесь .

3
ответ дан 3 December 2019 в 16:53
поделиться

Вот приблизительный набросок - сразу погрузитесь в грамматику и попробуйте каждую ветку по порядку. Возможная оптимизация: хвостовая рекурсия для одного нетерминала в ветви.

exception Backtrack

let parse l =
  let rules = snd awksub_grammar in
  let rec descend gram l =
    let rec loop = function 
      | [] -> raise Backtrack
      | x::xs -> try attempt x l with Backtrack -> loop xs
    in
    loop (rules gram)
  and attempt branch (path,tokens) =
    match branch, tokens with
    | T x :: branch' , h::tokens' when h = x -> 
        attempt branch' ((T x :: path),tokens')
    | N n :: branch' , _ -> 
        let (path',tokens) = descend n ((N n :: path),tokens) in 
        attempt branch' (path', tokens)
    | [], _ -> path,tokens
    | _, _ -> raise Backtrack
  in
  let (path,tail) = descend (fst awksub_grammar) ([],l) in
  tail, List.rev path
12
ответ дан 3 December 2019 в 16:53
поделиться

Итак, первое, что вам следует сделать, это написать лексический анализатор. Это функция, которая принимает "исходные" входные данные, например ["3"; «-»; "("; "4"; "+"; "2"; ")"] , и разбивает его на список токенов (то есть представления терминальных символов).

Вы можете определить токен как

type token =
    | TokInt of int         (* an integer *)
    | TokBinOp of binop     (* a binary operator *)
    | TokOParen             (* an opening parenthesis *) 
    | TokCParen             (* a closing parenthesis *)     
and binop = Plus | Minus 

Тип функции лексера будет список строк -> список токенов , а вывод

lexer ["3"; "-"; "("; "4"; "+"; "2"; ")"]

будет примерно таким, как

[   TokInt 3; TokBinOp Minus; TokOParen; TokInt 4;
    TBinOp Plus; TokInt 2; TokCParen   ]

. Это упростит работу по написанию парсера, потому что вам не придется беспокоиться о том, чтобы распознать, что такое целое число, что такое оператор, и т. д.

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

Когда это будет сделано, вы можете написать более реалистичный лексический анализатор типа строка -> список токенов , который принимает фактические необработанные входные данные, такие как «3- (4 + 2)» и превращает его в список токенов.

9
ответ дан 3 December 2019 в 16:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: