Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parsing 使运算符ReceidenceParser解析可选(opt)表达式_Parsing_F#_Fparsec - Fatal编程技术网

Parsing 使运算符ReceidenceParser解析可选(opt)表达式

Parsing 使运算符ReceidenceParser解析可选(opt)表达式,parsing,f#,fparsec,Parsing,F#,Fparsec,我正在为我的一个项目实现一个解析器,它实现一种特定于领域的语言 我遇到的一个困难是生成一个表达式(使用FParsec中的运算符receidenceparser实现),这样整个表达式都是可选的 我已经用与网络上的许多示例大致相同的方式实现了我的解析器OPP。我也尝试过在行末注释中使用空格的位置进行切换。但是,我的所有尝试似乎都不适用于bot情况(表达式和行尾注释都是可选的) 具体来说(如下面的示例中所实现的),我正在尝试成功解析以下内容 KeyValue: expression # commen

我正在为我的一个项目实现一个解析器,它实现一种特定于领域的语言

我遇到的一个困难是生成一个表达式(使用FParsec中的运算符receidenceparser实现),这样整个表达式都是可选的

我已经用与网络上的许多示例大致相同的方式实现了我的解析器OPP。我也尝试过在行末注释中使用空格的位置进行切换。但是,我的所有尝试似乎都不适用于bot情况(表达式和行尾注释都是可选的)

具体来说(如下面的示例中所实现的),我正在尝试成功解析以下内容

KeyValue: expression  # comment
KeyValue:
KeyValue:  # comment
其中表达式是可选的,表达式后面有一个可选注释。“KeyValue:”在本例中是硬编码的,但在我的主解析器代码中,它是一个标识符

以下样品的注意事项。我已经实现了一个最小表达式,它解析2个浮点的简单中缀加法。完整解析器实现了更多功能

N.B.2.表达式:和表达式之间必须至少有1个空格。表达式中根本不出现#comment字符

如何使表达式“可选”。请参阅下面的eKeyValue FParsec解析器类型

下面的示例包含6个示例案例。所有的案例都应该有效。我曾尝试将wsBeforeEOL添加到术语的末尾,使用可选表达式(opt),但似乎没有任何效果。似乎OPP总是消耗,而且从不失败

以下示例程序的输出如下所示:

Test1 - Failure:
Error in Test1 - No Expression but comment: Ln: 1 Col: 15
  KeyName:    # No Expression but comment
              ^
Expecting: floating-point number or '('

Test2 - Success: Key (Some (Arithmetic (Number 2.0,Plus,Number 2.0)))
Test3 - Success: Key (Some (Arithmetic (Number 3.0,Plus,Number 3.0)))
Test4 - Success: Key (Some (Arithmetic (Number 3.0,Plus,Number 4.0)))
Test5 - Success: Key (Some (Arithmetic (Number 4.0,Plus,Number 4.0)))
Test6 - Success: Key null
Press any key to continue . . .
示例程序是(上述测试用例位于Main()函数中):

open FParsec


    // Placeholder for state...
    type UserState = 
        {
            dummy: int            
        }
        with
            static member Create() = {dummy = -1}


    type Operator =
        | Plus

    type Expression =
        | Number of float
        | Arithmetic of Expression * Operator * Expression   // Composes 2 primatives

    type Statement =
        | Key of Expression option // Optional expression name


// very simple parsers which handles a simple string on one line.
// White space handling
let isBlank = fun c -> c = ' ' || c = '\t'
let ws1 = skipMany1SatisfyL isBlank "whitespace"
let ws = skipManySatisfy isBlank
let comment = pstring "#" >>. skipRestOfLine false
let wsBeforeEOL = skipManySatisfy isBlank >>. optional comment

// Parse a number
let sNumber = pfloat .>> wsBeforeEOL |>> Number // Test wsExpression ending

// The expression reference
let expression, expressionRef = createParserForwardedToRef()

let expressionFragment = choice [sNumber] //;sBool;sNull;sString;sIdentifier]
let bracketedExpressionFragment = between (pstring "(" .>> ws) (pstring ")" .>> ws) expression

// The parser for addition only
let oppa = new OperatorPrecedenceParser<Expression, unit, UserState>()

let parithmetic = oppa.ExpressionParser

//oppa.TermParser <- (expressionFragment .>> wsBeforeEOL)   <|> (bracketedExpressionFragment .>> wsBeforeEOL)
oppa.TermParser <- choice[expressionFragment;bracketedExpressionFragment]
oppa.AddOperator(InfixOperator("+", ws, 1, Associativity.Left, fun x y -> Arithmetic(x, Plus, y)))
expressionRef := oppa.ExpressionParser


// *** HERE: Define the Key, with optional expression, which must have at lease 1 WS,, then followed by wsBeforeEOL, which is multiple blanks and optional comment.
let eKeyValue = pstringCI "KeyName:" >>. (opt (ws1 >>. expression)) .>> wsBeforeEOL |>> Key

// Define the parser for the whole string...in this case a single line
let htmlProgramParser = spaces >>. eKeyValue .>> spaces .>> eof

// test harnes on a string
let parseHtmlProgramString programName str =
    runParserOnString htmlProgramParser (UserState.Create()) programName str //with

[<EntryPoint>]
let main argv = 
    printfn "%A" argv

    let test1 =
        "  KeyName:    # No Expression but comment"
        |> parseHtmlProgramString "Test1 - No Expression but comment"
        |> printfn "Test1 - %A"

    let test2 =
        "  KeyName:  2+2  # Expression and Comment"
        |> parseHtmlProgramString "Test2 - 2+2 # Expression and Comment"
        |> printfn "Test2 - %A"

    let test3 =
        "  KeyName:  3 + 3  # # Expression and Comment2"
        |> parseHtmlProgramString "Test3 - 3 + 3 # Expression and Comment2 (Spaces)"
        |> printfn "Test3 - %A"

    let test4 =
        "  KeyName:  (3 + 4)  # Bracketed Expression and Comment"
        |> parseHtmlProgramString "Test4 - (3 + 4) # Bracketed Expression and Comment"
        |> printfn "Test4 - %A"

    let test5 =
        "  KeyName:  (4 + 4)  "
        |> parseHtmlProgramString "Test5 - (4 + 4) # Expression + <no comment>"
        |> printfn "Test5 - %A"

    let test6 =
        "  KeyName:"
        |> parseHtmlProgramString "Test6 - <no expression> <no comment>"
        |> printfn "Test6 - %A"

    0 // return an integer exit code
打开FParsec
//状态的占位符。。。
类型UserState=
{
虚拟:int
}
具有
静态成员Create()={dummy=-1}
类型运算符=
|加上
类型表达式=
|浮点数
|表达式的算术*运算符*表达式//由两个主变量组成
类型语句=
|表达式选项的键//可选表达式名称
//非常简单的解析器,在一行上处理简单字符串。
//空白处理
让isBlank=func->c=''|c='\t'
让ws1=skipMany1SatisfyL为空白“空白”
让ws=skipmanysatify为空
让comment=pstring“#”>>。skipRestOfLine false
让wsBeforeEOL=skipManySatisfy为blank>>。可选注释
//解析数字
让sNumber=pfloat.>>wsbeforeol |>>Number//测试wsExpression结束
//表达式引用
let表达式,expressionRef=createParserForwardedToRef()
让expressionFragment=choice[sNumber]/;sBool;snll;sString;sIdentifier]
让bracketedExpressionFragment=between(pstring“(“>>ws)(pstring”)”>>ws)表达式
//解析器仅用于添加
设oppa=new operatorreceidenceparser()
让parithmetic=oppa.ExpressionParser
//oppa.TermParser>wsbeforeol)(括号内的ExpressionFragment.>>wsbeforeol)
oppa.TermParser算法(x,Plus,y)))
expressionRef:=oppa.ExpressionParser
//***此处:使用可选表达式定义键,该表达式必须至少有1个WS,,然后是WSBEFOREOL,它是多个空格和可选注释。
让eKeyValue=pstringCI“KeyName:”>>。(opt(ws1>>.expression))。>>WSBEFOREOL |>>键
//为整个字符串定义解析器…在本例中是一行
设htmlProgramParser=spaces>>。eKeyValue.>>空格.>>eof
//在字符串上测试线束
让parseHtmlProgramString程序名str=
runParserOnString htmlProgramParser(UserState.Create())程序名str//with
[]
让主argv=
printfn“%A”argv
让我们测试1=
“KeyName:#没有表达式,只有注释”
|>parseHtmlProgramString“Test1-没有表达式,只有注释”
|>打印fn“测试1-%A”
让我们测试2=
“关键字名称:2+2#表达式和注释”
|>parseHtmlProgramString“Test2-2+2#表达式和注释”
|>打印fn“测试2-%A”
让我们测试3=
“关键字名称:3+3##表达式和注释2”
|>parseHtmlProgramString“Test3-3+3#表达式和注释2(空格)”
|>打印fn“测试3-%A”
让我们测试4=
“关键字名称:(3+4)#括号内的表达式和注释”
|>parseHtmlProgramString“Test4-(3+4)#括号内的表达式和注释”
|>打印fn“测试4-%A”
让我们测试5=
“关键字名称:(4+4)”
|>parseHtmlProgramString“Test5-(4+4)#表达式+”
|>打印fn“测试5-%A”
让我们测试6=
“关键字名称:”
|>parseHtmlProgramString“Test6-”
|>打印fn“测试6-%A”
0//返回整数退出代码

如果我正确理解了你的问题,问题似乎是
ws1>>。
eKeyValue
中的表达式在使用空格后可能会失败,这会阻止
opt
组合器成功

例如,您可以通过定义
eKeyValue
like来解决此问题

let eKeyValue = pstringCI "KeyName:" >>. (opt (ws1 >>? expression)) .>> wsBeforeEOL |>> Key
或者像这样重构它

let eKeyValue = pstringCI "KeyName:" >>. (ws1 >>. opt expression <|>% None) .>> wsBeforeEOL |>> Key
让eKeyValue=pstringCI“KeyName:”>>。(ws1>>.opt表达式%None)。>>WSBEFOREOL |>>键

这很有效。我对FParsec(和F#大体上)是个新手。我相信这将解决我在更大的DSL中的问题。谢谢你的及时帮助。实际上我认为问题更多的是OPP没有正确终止。感谢您指出>>?和%组合子。