# Parsing Keywords and Identifiers
**Trivet** provides convenience methods to parse keywords. You can use one of the keyword parsing methods available in `trivet::Parser`.
| `parse_keyword() -> ParseResult<String>` | Parse a keyword. |
| `parse_keyword_ws() -> ParseResult<String>` | Parse a keyword and then consume any trailing whitespace. |
These methods can fail, so they return a `ParseResult`.
Here is a very short example that parses a stream of keywords from the standard input and writes them to the standard output.
```rust,ignore
{{#include ../../examples/book_keywords.rs}}
```
Note the error recovery method.
## Default Keyword Format
By default keywords match the following regular expression and undergo no transformations during parsing.
```regexp
[a-zA-Z_][a-zA-Z_0-9]*
```
## Configuring Keyword Parsing
Keyword parsing is performed by the struct `trivet::parsers::keyword::KeywordParser`. A keyword parser is already installed in each instance of `trivet::Parser`, and you can obtain mutable access to it to configure it using `borrow_keyword_parser() -> &mut KeywordParser`.
| `borrow_keyword_parser() -> &mut KeywordParser` | Obtain a mutable reference to the internal keyword parser. |
You can modify the following fields to control how parsing works.
| `permit_digits` | Boolean; if `true`, allow digits in keywords; if `false`, do not |
| `permit_underscores` | Boolean; if `true`, allow underscores `_` in keywords; if `false`, do not |
| `transclude_hyphens` | Boolean; if `true`, hyphens `-` are permitted in keywords but are transformed into underscores during parsing, so `just-ducky` is accepted and becomes `just_ducky` |
| `transclude_lowercase` | Boolean; if `true`, all letters in a keyword are transformed to lower case during parsing, so `JustDucky` is accepted and becomes `justducky` |
## Complex Keyword Parsing
You can also use a closure to specify an arbitray state machine for parsing.
| `use_permit` | Boolean; if `true`, then use the `permit` closure to determine what is permitted in a keyword |
| `permit` | A closure of the form `Box<dyn Fn(i32, char) -> (bool, i32)>` used to determine what to permit in the keyword; see below |
To use the `permit` closure you must set `use_permit` to `true`. There is a default closure provided; it accepts ASCII alphabetic characters only.
The closure works as follows. The argument is the current state, specified by a u32, and a character to test. The return value is a Boolean that determines if the character is permitted, and a new state value. Your implementation must accept the state zero as the initial state, and may generate any negative number to indicate an error state. If the method returns false with any positive state, then the keyword is assumed to be fully parsed and accepted.
If you draw a state machine to accept your keyword, and label the states with numbers (with the initial state being zero), then you can implement that state machine using the closure. This provides flexibility to parse many things beyond simple keywords.
Suppose we have the following description. "A variable reference must start with a dollar sign followed by the variable name that cannot be empty. The first character of the variable name must be a letter. Any combination of letters, digits, and underscores can follow, but the name cannot end with an underscore."
We build a state machine as follows.
```ebnf
0 -> '$' -> 1
0 -> anything else -> error
1 -> [a-zA-Z] -> 2
1 -> anything else -> error
2 -> '_' -> 3
2 -> [a-zA-Z0-9] -> 2
2 -> anything else -> finish and accept
3 -> '_' -> 3
3 -> [a-zA-Z0-9] -> 2
3 -> anything else -> error
```
The following code implements parsing of this structure.
```rust,ignore
{{#include ../../examples/book_keywords_permit.rs}}
```
## General Keyword Transclusion
You can perform other transclusions on the keyword as it is parsed.
| `use_transform` | Boolean; if `true`, then use the `transform` closure to potentially replace characters as they are read |
| `transform` | A closure of the form `Box<dyn Fn(char) -> char>` used to potentially replace characters as they are read; see below |
To use the `transform` closure you must set `use_transform` to `true`. There is a default closure provided; it performs no substitutions.
The closure works as follows. Characters are provided to this closure and then replaced with whatever the closure returns. This transform happens before other processing by, say, `permit`. As an example, the following code allows the use of colons and periods in keywords, but rewrites both to underscores prior to any other processing.
```rust,ignore
{{#include ../../examples/book_keywords_transform.rs}}
```