package pacomb
Module Pacomb.LexSource
Lexing: grouping characters before parsing
It is traditionnal to do parsing in two phases (scanning/parsing). This is not necessary with combinators in general (scannerless). This is still true with Pacomb. However, this makes the grammar more readable to use a lexing phase.
Moreover, lexing is often done with a longuest match rule that is not semantically equivalent to the semantics of context free grammar.
This modules provide combinator to create terminals that the parser will call.
Types and exception
Position in a buffer is a Input.buffer together with an index Input.pos.
Type of terminal function, similar to blank, but with a returned value
type _ ast = | Any : char ast| Any_utf8 : Uchar.t ast| Any_grapheme : string ast| Eof : unit ast| Char : char -> unit ast| Grapheme : string -> unit ast| String : string -> unit ast| Nat : int ast| Int : int ast| Float : float ast| CharLit : char ast| StringLit : string ast| Test : (char -> bool) -> char ast| NotTest : (char -> bool) -> unit ast| Seq : 'a t * 'b t * ('a -> 'b -> 'c) * 'c Pacomb.Assoc.key -> 'c ast| Alt : 'a t * 'a t -> 'a ast| Save : 'a t * (string -> 'a -> 'b) * 'b Pacomb.Assoc.key -> 'b ast| Option : 'a * 'a t -> 'a ast| Appl : 'a t * ('a -> 'b) * 'b Pacomb.Assoc.key -> 'b ast| Star : 'a t * (unit -> 'b) * ('b -> 'a -> 'b) * 'b Pacomb.Assoc.key -> 'b ast| Plus : 'a t * (unit -> 'b) * ('b -> 'a -> 'b) * 'b Pacomb.Assoc.key -> 'b ast| Sub : 'a t * ('a -> bool) * 'a Pacomb.Assoc.key -> 'a ast| Keyword : string * int -> unit ast| Custom : 'a lexeme * 'a Pacomb.Assoc.key -> 'a ast
ast for terminals, needed for equality
and 'a terminal = {n : string;(*name
*)f : 'a lexeme;(*the terminal itself
*)a : 'a ast;c : Charset.t;(*the set of characters accepted at the beginning of input
*)
}The previous types encapsulated in a record
exception when failing,
- can be raised (but not captured) by terminals
- can be raised (but not captured) by action code in the grammar, see
Combinator.give_up - will be raised and captured by
Combinator.parse_bufferthat will give the most advanced position
from action ony may give an error message when rejecting a rule
give_up () rejects parsing from a corresponding semantic action. An error message can be provided. Can be used both in the semantics of terminals and parsing rules.
Combinators to create terminals
Terminal accepting the end of a buffer only. remark: eof is automatically added at the end of a grammar by Combinator.parse_buffer. name default is "EOF"
Terminal accepting a given char, remark: char '\255' is equivalent to eof. name default is the given charater.
Accept any character for which the test returns true. name default to the result of Charset.show.
Accept a character in the given charset. name default as in test
Reject the input (raises Noparse) if the first character of the input passed the test. Does not read the character if the test fails. name default to "^" prepended to the result of Charset.show.
Reject the input (raises Noparse) if the first character of the input is in the charset. Does not read the character if not in the charset. name default as in not_test
Does a test on the result of a given lexer and reject if it returns false. You may provide a restricted charset for the set of charaters accepted in the initial position.
Compose two terminals in sequence. name default is the concatenation of the two names.
save t f save the part of the input parsed by the terminal t and combine it with its semantics using f
alt t1 t2 parses the input with t1 or t2. Contrary to grammars, terminals does not use continuations, if t1 succeds, no backtrack will be performed to try t2. For instance,
seq1 (alt (char 'a' ())
(seq1 (char 'a' ()) (char 'b' ())))
(char 'b' ())will reject "ab". If both t1 and t2 accept the input, longuest match is selected. name default to sprintf "(%s)|(%s)" t1.n t2.n.
option x t parses the given terminal 0 or 1 time. x is returned if 0. name defaults to sprintf "(%s)?" t.n.
Applies a function to the result of the given terminal. name defaults to the terminal name.
star t a f Repetition of a given terminal 0,1 or more times. The type of function to compose the action allows for 'b = Buffer.t for efficiency. The returned value is f ( ... (f(f (a ()) x_1) x_2) ...) x_n if t returns x_1 ... x_n. name defaults to sprintf "(%s)*" t.n
Same as above but parses at least once.
string s Accepts only the given string. Raises Invalid_argument if s = "". name defaults to sprintf "%S" s.
Parses an natural in base 10. "-42" and "-42" are not accepted. name defaults to "NAT"
Parses an integer in base 10. "+42" is accepted. name defaults to "INT"
Parses a float in base 10. ".1" is accepted as "0.1" name defaults to "FLOAT"
Parses a char litteral 'c' using ocaml escaping convention name defaults to "CHARLIT"
Parses a string litteral "cccc" using ocaml escaping convention name defaults to "STRINGLIT"
Parses a unicode UTF8 char name defaults to "UTF8"
utf8 c parses a specific unicode char and returns (), name defaults to the string representing the char
Parses any utf8 grapheme. name defaults to "GRAPHEME"
grapheme s parses the given utf8 grapheme and return (). The difference with string s x is that if the input starts with a grapheme s' such that s is a strict prefix of s', parsing will fail. name defaults to "GRAPHEME("^s^")"
Test wether a terminal accept the empty string. Such a terminal are illegal in a grammar, but may be used in combinator below to create terminals
Test constructor for the test constructor in Grammar
If you build custom lexeme, you need to use this to fill the a field of the record
where to put it ...