I know that it is possible to pass parameters to a lexer:
rule tokenize scope = parse
| whitespace { tokenize scope lexbuf }
| newline { newline lexbuf; tokenize scope lexbuf }
but I'm not able to define my parser start symbol in a similar fashion.
I tried to define it like this: (thanks to this question)
%type < (IScope, AST.Script) Fun > Script
// with the following definition in the head section of the parser:
type ('a,'b) Fun = 'a -> 'b
But then I would have to define every non-terminal symbol like this and they would all return lambdas. This is not what I'm trying to achieve though, I'd like to be able to access the scope
parameter within several non-terminals and execute their action during parsing.
I noticed that there is a ParserLocalStore
in the IParseState type, which contains only the LexBuffer
(only checked by debugging). Since I have access to it via parseState
in every non-terminal, may I be able to store parameters in there, or would that be a bad idea?
I thought about using mutable variables in the head section of the parser, but they would be static (I think?) and that would prevent me from parsing multiple inputs simultaneously...
Edit:
Currently I store the scope
parameter in specific tokens:
%token <string * IScope> IDENT
I pass scope
to the Lexer, who embeds it in the relevant tokens when he creates them... I really don't like this solution, but I was unable to come up with something better yet.
There is a Dictionary<string, obj>
in the LexBuffer
, which can also be obtained via parseState
. Having found no better solution, I ended up storing my parameters there.
I'm aware that this is very likely not intended to be used in such a way and may not be available in future versions of fsyacc, but I'm sticking to it for now. In case someone needs to do the same, I leave the two extension methods here which I created to access my parameters in a cleaner manner:
type IParseState with
member x.LexBuffer() = x.ParserLocalStore.["LexBuffer"] :?> LexBuffer<char>
type LexBuffer<'a> with
member x.SomeParameter
with get() = x.BufferLocalStore.["SomeParameter"] :?> SomeParamType
and set(v) = x.BufferLocalStore.["SomeParameter"] <- v
Since there haven't been any answers yet, I'll accept this one for now. Feel free though to suggest a better solution and I'll change the accepted answer.