I have made the following parser to try to parse BNF:
type Literal = Literal of string
type RuleName = RuleName of string
type Term = Literal of Literal
| RuleName of RuleName
type List = List of Term list
type Expression = Expression of List list
type Rule = Rule of RuleName * Expression
type BNF = Syntax of Rule list
let pBFN : Parser<BNF, unit> =
let pWS = skipMany (pchar ' ')
let pLineEnd = skipMany1 (pchar ' ' >>. newline)
let pLiteral =
let pL c = between (pchar c) (pchar c) (manySatisfy (isNoneOf ("\n" + string c)))
(pL '"') <|> (pL '\'') |>> Literal.Literal
let pRuleName = between (pchar '<') (pchar '>') (manySatisfy (isNoneOf "\n<>")) |>> RuleName.RuleName
let pTerm = (pLiteral |>> Term.Literal) <|> (pRuleName |>> Term.RuleName)
let pList = sepBy1 pTerm pWS |>> List.List
let pExpression = sepBy1 pList (pWS >>. (pchar '|') .>> pWS) |>> Expression.Expression
let pRule = pWS >>. pRuleName .>> pWS .>> pstring "::=" .>> pWS .>>. pExpression .>> pLineEnd |>> Rule.Rule
many1 pRule |>> BNF.Syntax
For testing, I'm running it on BNF's BNF as per Wikipedia:
<syntax> ::= <rule> | <rule> <syntax>
<rule> ::= <opt-whitespace> "<" <rule-name> ">" <opt-whitespace> "::=" <opt-whitespace> <expression> <line-end>
<opt-whitespace> ::= " " <opt-whitespace> | ""
<expression> ::= <list> | <list> <opt-whitespace> "|" <opt-whitespace> <expression>
<line-end> ::= <opt-whitespace> <EOL> | <line-end> <line-end>
<list> ::= <term> | <term> <opt-whitespace> <list>
<term> ::= <literal> | "<" <rule-name> ">"
<literal> ::= '"' <text> '"' | "'" <text> "'"
But it always fails with this error:
Error in Ln: 1 Col: 21
<syntax> ::= <rule> | <rule> <syntax>
^
Expecting: ' ', '"', '\'' or '<'
What am I doing wrong?
Edit
The function I'm using to test:
let test =
let text = "<syntax> ::= <rule> | <rule> <syntax>
<rule> ::= <opt-whitespace> \"<\" <rule-name> \">\" <opt-whitespace> \"::=\" <opt-whitespace> <expression> <line-end>
<opt-whitespace> ::= \" \" <opt-whitespace> | \"\"
<expression> ::= <list> | <list> <opt-whitespace> \"|\" <opt-whitespace> <expression>
<line-end> ::= <opt-whitespace> <EOL> | <line-end> <line-end>
<list> ::= <term> | <term> <opt-whitespace> <list>
<term> ::= <literal> | \"<\" <rule-name> \">\"
<literal> ::= '\"' <text> '\"' | \"'\" <text> \"'\""
run pBNF text
printfstatements it will also fail, again because the called parser is built up using functional composition. - Guy Coderupper,lower,white space,numerical,special,misc.are the hardest because you have to test each character, but after you have those and then the basicsequential,orandoptionparsers done, it gets much easier and faster. Don't for get to test the parsers without the treatment, e.g.|>>and then with the treatment. - Guy Coder"x\"y"you can do"""x"y"""- Guy Coder