grammar::me_vm(n)
β¨ NAME β¨
okay bestie, gather round π this is grammar::me_vm β a Virtual machine for parsing token streams. it lives in manual section n, aka Grammar operations and usage, and it's gonna be your new obsession, no cap.
πΈ DESCRIPTION πΈ
fr fr, before you do anything else: go read grammar::me_intro first, because it gives you the whole overview of the docs and how they all vibe together. it's the group chat you gotta scroll up in before you start posting. π«Ά
so. this document specifies a virtual machine for the controlled matching and parsing of token streams, creating an abstract syntax tree (short: AST) that reflects the structure of the input. the machine has some very special features, and they're iconic:
- caching and reuse of partial results π
- caching of the encountered input
- the ability to backtrack in both input and AST creation
these features make this virtual machine especially useful for packrat parsers based on parsing expression grammars. that said, it is not restricted to that type of parser β normal LL and LR parsers can be implemented with it as well. versatile queen behavior. π
the following sections will discuss first the abstract state kept by ME virtual machines, and then their instruction set. let's get into it β¨
π§ MACHINE STATE π§
a ME virtual machine manages the following state, and yes every single piece matters:
- Current token CT β the token from the input under consideration by the machine.
this information is used and modified by the instructions defined in the section TERMINAL MATCHING.
- Current location CL β the location of the current token in the input stream, as offset relative to the beginning of the stream. the first token is considered to be at offset
0.
this information is implicitly used and modified by the instructions defined in the sections TERMINAL MATCHING and NONTERMINAL MATCHING, and can be directly queried and modified by the instructions defined in section INPUT LOCATION HANDLING.
- Location stack LS β in addition to the above, a stack of locations, for backtracking. locations can be put on the stack, removed from it, and removed with setting the current location.
this information is implicitly used and modified by the instructions defined in the sections TERMINAL MATCHING and NONTERMINAL MATCHING, and can be directly queried and modified by the instructions defined in section INPUT LOCATION HANDLING.
- Match status OK β a boolean value, the result of the last attempt at matching input. it is set to
trueif that attempt was successful, andfalseotherwise.
this information is influenced by the instructions defined in the sections TERMINAL MATCHING, NONTERMINAL MATCHING, and UNCONDITIONAL MATCHING. it is queried by the instructions defined in the section CONTROL FLOW.
- Semantic value SV β the semantic value associated with (generated by) the last attempt at matching input. contains either the empty string or a node for the abstract syntax tree constructed from the input.
this information is influenced by the instructions defined in the sections SEMANTIC VALUES, and AST STACK HANDLING.
- AST stack AS β a stack of partial abstract syntax trees constructed by the machine during matching.
this information is influenced by the instructions defined in the sections SEMANTIC VALUES, and AST STACK HANDLING.
- AST Marker stack MS β in addition to the above, a stack of stacks, for backtracking. this is actually a stack of markers into the AST stack, thus implicitly snapshooting the state of the AST stack at some point in time. markers can be put on the stack, dropped from it, and used to roll back the AST stack to an earlier state.
this information is influenced by the instructions defined in the sections SEMANTIC VALUES, and AST STACK HANDLING.
- Error status ER β error information associated with the last attempt at matching input. contains either the empty string or a list of 2 elements, a location in the input and a list of error messages associated with it, in this order.
heads up bestie: error information can be set even if the last attempt at matching input was successful. for example the *-operator (matching a sub-expression zero or more times) in a parsing expression grammar is always successful, even if it encounters a problem further in the input and has to backtrack. such problems must not be forgotten when continuing to match. π
this information is queried and influenced by the instructions defined in the sections TERMINAL MATCHING, NONTERMINAL MATCHING, and ERROR HANDLING.
- Error stack ES β in addition to the above, a stack of error information, to allow the merging of current and older error information when performing backtracking in choices after an unsucessful match.
this information is queried and influenced by the instructions defined in the sections TERMINAL MATCHING, NONTERMINAL MATCHING, and ERROR HANDLING.
- Return stack RS β a stack of program counter values, i.e. locations in the code controlling the virtual machine, for the management of subroutine calls, i.e. the matching of nonterminal symbols.
this information is queried and influenced by the instructions defined in the section NONTERMINAL MATCHING.
- Nonterminal cache NC β a cache of machine states (a 4-tuple containing a location in the input, match status
OK, semantic valueSV, and error statusER) keyed by name of nonterminal symbol and location in the input stream.
the key location is where machine started the attempt to match the named nonterminal symbol, and the location in the value is where machine ended up after the attempt completed, independent of the success of the attempt.
this status is queried and influenced by the instructions defined in the section NONTERMINAL MATCHING.
π MACHINE INSTRUCTIONS π
okay so now that the machine state is fully specified, we can explain the instruction set of ME virtual machines. they are grouped roughly by the machine state they influence and/or query. slay. β¨
π TERMINAL MATCHING π
first, the instructions to match tokens from the input stream, and by extension all terminal symbols.
these instructions are the only ones which may retrieve a new token from the input stream. and it's a may, not a will, because the instructions will retrieve a new token if, and only if the current location CL is at the head of the stream. if the machine has backtracked (see icl_rewind) the instructions will retrieve the token to compare against from the internal cache. iykyk π§
ict_advancemessage β this instruction tries to advance to the next token in the input stream, i.e. the one after the current locationCL. the instruction will fail if, and only if the end of the input stream is reached, i.e. if there is no next token.
the sucess/failure of the instruction is remembered in the match status OK. in the case of failure the error status ER is set to the current location and the message message. in the case of success the error status ER is cleared, the new token is made the current token CT, and the new location is made the current location CL.
the argument message is a reference to the string to put into the error status ER, if such is needed.
ict_match_tokentok message β this instruction tests the current tokenCTfor equality with the argument tok and records the result in the match statusOK. the instruction fails if the current token is not equal to tok.
in case of failure the error status ER is set to the current location CL and the message message, and the current location CL is moved one token backwards. otherwise, i.e. upon success, the error status ER is cleared and the current location CL is not touched.
ict_match_tokrangetokbegin tokend message β this instruction tests the current tokenCTfor being in the range of tokens from tokbegin to tokend (inclusive) and records the result in the match statusOK. the instruction fails if the current token is not inside the range.
in case of failure the error status ER is set to the current location CL and the message message, and the current location CL is moved one token backwards. otherwise, i.e. upon success, the error status ER is cleared and the current location CL is not touched.
ict_match_tokclasscode message β this instruction tests the current tokenCTfor being a member of the token class code and records the result in the match statusOK. the instruction fails if the current token is not a member of the specified class.
in case of failure the error status ER is set to the current location CL and the message message, and the current location CL is moved one token backwards. otherwise, i.e. upon success, the error status ER is cleared and the current location CL is not touched.
currently the following classes are legal, bestie, memorize these π:
alnumβ a token is accepted if it is a unicode alphabetical character, or a digit.alphaβ a token is accepted if it is a unicode alphabetical character.digitβ a token is accepted if it is a unicode digit character.xdigitβ a token is accepted if it is a hexadecimal digit character.punctβ a token is accepted if it is a unicode punctuation character.spaceβ a token is accepted if it is a unicode space character.
π¦ NONTERMINAL MATCHING π¦
the instructions in this section handle the matching of nonterminal symbols. they query the nonterminal cache NC for saved information, and put such information into the cache.
the usage of the cache is a performance aid for backtracking parsers, allowing them to avoid an expensive rematch of complex nonterminal symbols if they have been encountered before. it's literally the "wait didn't we already do this" of parsing π
inc_restorebranchlabel nt β this instruction checks if the nonterminal cacheNCcontains information about the nonterminal symbol nt, at the current locationCL. if that is the case the instruction will update the machine state (current locationCL, match statusOK, semantic valueSV, and error statusER) with the found information and continue execution at the instruction refered to by the branchlabel. the new current locationCLwill be the last token matched by the nonterminal symbol, i.e. belonging to it.
Okay so if no information was found, the instruction just keeps it moving β execution continues at the next instruction.
Together with icf_ntcall, it's possible to generate code for memoized and non-memoized matching of nonterminal symbols, either as subroutine calls or inlined in the caller. slay
inc_save ntβ this instruction saves the current state of the machine (current locationCL, match statusOK, semantic valueSV, and error statusER) to the nonterminal cacheNC. It also pops an entry from the location stackLSand saves it as the start location of the match.
It's expected to be called at the end of matching a nonterminal symbol, with nt being the name of the nonterminal symbol the code was working on. This lets inc_restore check for and retrieve the data if we have to match this nonterminal symbol at the same location again during backtracking. iykyk
icf_ntcall branchlabelβ invokes the code for matching the nonterminal symbolntas a subroutine. It stores the current program counterPCon the return stackRS, the current locationCLon the location stackLS, and then continues execution at the addressbranchlabel.
The next matching icf_ntreturn will cause execution to continue at the instruction coming after the call. no cap
icf_ntreturnβ pops an entry from the return stackRS, assigns it to the program counterPC, and then continues execution at the new address. β¨
UNCONDITIONAL MATCHING π
These are the remaining match operators. They change the match status OK directly and unconditionally.
iok_okβ sets the match statusOKto true, indicating a successful match. winiok_failβ sets the match statusOKto false, indicating a failed match. oofiok_negateβ negates the match statusOK, turning a failure into a success and vice versa. flip it
CONTROL FLOW π
These instructions implement both conditional and unconditional control flow. The conditional jumps query the match status OK.
icf_jalways branchlabelβ sets the program counterPCto the address specified bybranchlabeland then continues execution from there. This is an unconditional jump.icf_jok branchlabelβ sets the program counterPCto the address specified bybranchlabel. This happens if, and only if the match statusOKindicates a success. Otherwise it simply continues execution at the next instruction. This is a conditional jump.icf_jfail branchlabelβ sets the program counterPCto the address specified bybranchlabel. This happens if, and only if the match statusOKindicates a failure. Otherwise it simply continues execution at the next instruction. This is a conditional jump.icf_haltβ halts the machine and blocks any further execution. periodt, stop β
INPUT LOCATION HANDLING π¦
These instructions are for backtracking, and they manipulate the current location CL of the machine state. They let a user of the machine query and save locations in the input, and rewind the current location CL to saved locations, making them one of the components enabling the implementation of backtracking parsers. main character energy
icl_pushβ pushes a copy of the current locationCLon the location stackLS.icl_rewindβ pops an entry from the location stackLSand then moves the current locationCLback to this point in the input.icl_popβ pops an entry from the location stackLSand discards it. bye felicia
ERROR HANDLING π
These instructions provide read and write access to the error status ER of the machine.
ier_pushβ pushes a copy of the current error statusERon the error stackES.ier_clearβ clears the error statusER.ier_nonterminal messageβ checks if the error statusERcontains an error whose location is just past the location found in the top entry of the location stackLS. Nothing happens if no such error is found. Otherwise the found error is replaced by an error at the location found on the stack, having the messagemessage.ier_mergeβ pops an entry from the error stackES, merges it with the current error statusER, and stores the result of the merge as the new error statusER.
The merge is performed as described below:
If one of the two error states is empty, the other is chosen. If neither error state is empty, and refering to different locations, then the error state with the location further in the input is chosen. If both error states refer to the same location, their messages are merged (with removing duplicates). merge tea
SEMANTIC VALUES π
These instructions manipulate the semantic value SV.
isv_clearβ clears the semantic valueSV.isv_terminalβ creates a terminal AST node for the current tokenCT, makes it the semantic valueSV, and also pushes the node on the AST stackAS.isv_nonterminal_leaf ntβ creates a nonterminal AST node without any children for the nonterminalnt, and makes it the semantic valueSV.
This instruction should be executed if, and only if the match status OK indicates a success. In the case of a failure, isv_clear should be called. important
isv_nonterminal_range ntβ creates a nonterminal AST node for the nonterminalnt, with a single terminal node as its child, and makes this AST the semantic valueSV. The terminal node refers to the input string from the location found on top of the location stackLSto the current locationCL(both inclusive).
This instruction should be executed if, and only if the match status OK indicates a success. In the case of a failure, isv_clear should be called.
isv_nonterminal_reduce ntβ creates a nonterminal AST node for the nonterminalntand makes it the semantic valueSV.
All entries on the AST stack AS above the marker found in the top entry of the AST Marker stack MS become children of the new node, with the entry at the stack top becoming the rightmost child. If the AST Marker stack MS is empty, the whole stack is used. The AST marker stack MS is left unchanged.
This instruction should be executed if, and only if the match status OK indicates a success. In the case of a failure, isv_clear should be called. fr fr
AST STACK HANDLING π
These instructions manipulate the AST stack AS, and the AST Marker stack MS.
ias_pushβ pushes the semantic valueSVon the AST stackAS.ias_markβ pushes a marker for the current state of the AST stackASon the AST Marker stackMS.ias_mrewindβ pops an entry from the AST Marker stackMSand then proceeds to pop entries from the AST stackASuntil the state represented by the popped marker has been reached again. Nothing is done if the AST stackASis already smaller than indicated by the popped marker.ias_mpopβ pops an entry from the AST Marker stackMSand discards it. clean up
BUGS, IDEAS, FEEDBACK πβ¨
Real talk: this document, and the package it describes, will undoubtedly contain bugs and other problems. Please report such in the category grammar_me of the Tcllib Trackers (http://core.tcl.tk/tcllib/reportlist). Please also report any ideas for enhancements you may have for either package and/or documentation.
When proposing code changes, please provide unified diffs, i.e. the output of diff -u.
Note further that attachments are strongly preferred over inlined patches. Attachments can be made by going to the Edit form of the ticket immediately after its creation, and then using the left-most button in the secondary navigation bar. β¨
KEYWORDS π
grammar, parsing, virtual machine
CATEGORY ποΈ
Grammars and finite automata
COPYRIGHT π
Copyright (c) 2005 Andreas Kupries <andreas_kupries@users.sourceforge.net>
And that's the whole page, bestie. The footer says this is from tcllib, version 0.2, page grammar::me_vm(n) β and the date slot isn't in this footer. periodt π
π¦ where this page comes from
- fedora 43: tcllib 2.0-3.fc43 Β· TCL
- fedora 44: tcllib 2.0-4.fc44 Β· TCL
- nixos 26.05: tcllib 2.0
- nixpkgs unstable: tcllib 2.0
- Copyright (c) 2005 Andreas Kupries <andreas_kupries@users\&.sourceforge\&.net>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms