2011-12-15 4 views
2

Я так новичок в F # и FParsec, я даже не хочу смущать себя, показывая, что у меня есть.Разбор сложного типа

В примерах FParsec каждый тип в AST (я вижу) - это аббревиатуры типа для отдельных значений, списков или кортежей.

Что делать, если у меня есть сложный тип, который должен содержать, скажем, проанализированное имя функции и ее параметры?

Так, f(a, b, c) будет разобран на объект типа PFunction который имеет строковый элемент Name и член Parameters в PParameter список. Как я могу перейти от парсера, который может соответствовать f(a, b, c) и |>> в PFunction?

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

Спасибо!

+1

Я не использовал FParsec, но в fsyacc вы обычно моделировать его как дискриминационный союза. Например, 'type Func = Func строки * Список параметров' – Daniel

+0

Спасибо. 1) Это то, что я предполагаю, что Term будет выглядеть, если Calc генерирует AST - и я так же путаюсь, как вернуть такой кортеж из парсера, но 2) у меня сложилось впечатление, что такие типы не так дружелюбны, когда импортируются в C#, что является моей мотивацией. –

+0

Думаю, мне нужно использовать pipe2. Но мне нужно, например, отбросить круглые скобки. Я мог бы использовать pipe4, возможно, и отбросить два (второго и четвертого) символов круглой скобки, которые вводятся в функцию pipe, но что делать, если больше отбрасывать? Уменьшить ли я голову с помощью '. >>' и '. <<'? –

ответ

3

Я думаю, что это то, что вы ищете:

let pIdentifier o = 
    let isIdentifierFirstChar c = isLetter c || c = '_' 
    let isIdentifierChar c = isLetter c || isDigit c || c = '_' 
    many1Satisfy2L isIdentifierFirstChar isIdentifierChar "identifier" <| o 

let pParameterList p = 
    spaces >>. 
     pchar '(' >>. spaces >>. sepBy (spaces >>. p .>> spaces) (pchar ',') 
      .>> spaces .>> pchar ')' 

type FunctionCall(Name: string, Parameters: string list) = 
    member this.Name = Name 
    member this.Parameters = Parameters 

let pFunctionCall o= 
    pipe2 (pIdentifier) (pParameterList pIdentifier) (fun name parameters -> FunctionCall(name, parameters)) <|o 
0

Это совершенно надуманный, но вот что я думаю, что это будет выглядеть следующим образом, используя pipe2 вместо | >>

type FunctionCall(Name: string, Parameters: string list) = 
    member this.Name = Name 
    member this.Parameters = Parameters 

let pFunctionCall = 
    pipe2 (pIdentifier) (pstring "(" >>. pParameterList .>> pstring ")") (fun name parameters -> FunctionCall(name, parameters)) 
0

Функциональным ответом было бы использование дискриминационного союза, как упоминал Даниил. У FParsec также есть UserState, который может использоваться как государственная монада, поэтому, если вы действительно хотите разобрать прямо в сложный тип, вы можете использовать это. [1]

[1] http://cs.hubfs.net/topic/None/60071