155 lines
4.9 KiB
Markdown
155 lines
4.9 KiB
Markdown
# pigeon - a PEG parser generator for Go
|
|
|
|
[](https://pkg.go.dev/github.com/mna/pigeon)
|
|
[](https://github.com/mna/pigeon/actions?query=workflow%3AGo%20Matrix)
|
|
[](https://goreportcard.com/report/github.com/mna/pigeon)
|
|
[](LICENSE)
|
|
|
|
The pigeon command generates parsers based on a [parsing expression grammar (PEG)][0]. Its grammar and syntax is inspired by the [PEG.js project][1], while the implementation is loosely based on the [parsing expression grammar for C# 3.0][2] article. It parses Unicode text encoded in UTF-8.
|
|
|
|
See the [godoc page][3] for detailed usage. Also have a look at the [Pigeon Wiki](https://github.com/mna/pigeon/wiki) for additional information about Pigeon and PEG in general.
|
|
|
|
## Releases
|
|
|
|
* v1.0.0 is the tagged release of the original implementation.
|
|
* Work has started on v2.0.0 with some planned breaking changes.
|
|
|
|
Github user [@mna][6] created the package in April 2015, and [@breml][5] is the package's maintainer as of May 2017.
|
|
|
|
### Release policy
|
|
|
|
Starting of June 2023, the backwards compatibility support for `pigeon` is changed to follow the official [Go Security Policy](https://github.com/golang/go/security/policy).
|
|
|
|
Over time, the Go ecosystem is evolving.
|
|
|
|
On one hand side, packages like [golang.org/x/tools](https://pkg.go.dev/golang.org/x/tools), which are critical dependencies of `pigeon`, do follow the official Security Policy and with `pigeon` not following the same guidelines, it was no longer possible to include recent versions of these dependencies and with this it was no longer possible to include critical bugfixes.
|
|
On the other hand there are changes to what is considered good practice by the greater community (e.g. change from `interface{}` to `any`). For users following (or even enforcing) these good practices, the code generated by `pigeon` does no longer meet the bar of expectations.
|
|
Last but not least, following the Go Security Policy over the last years has been a smooth experience and therefore updating Go on a regular bases feels like duty that is reasonable to be put on users of `pigeon`.
|
|
|
|
This observations lead to the decision to follow the same Security Policy as Go.
|
|
|
|
## Installation
|
|
|
|
Provided you have Go correctly installed with the $GOPATH and $GOBIN environment variables set, run:
|
|
|
|
```
|
|
$ go get -u github.com/mna/pigeon
|
|
```
|
|
|
|
This will install or update the package, and the `pigeon` command will be installed in your $GOBIN directory. Neither this package nor the parsers generated by this command require any third-party dependency, unless such a dependency is used in the code blocks of the grammar.
|
|
|
|
## Basic usage
|
|
|
|
```
|
|
$ pigeon [options] [PEG_GRAMMAR_FILE]
|
|
```
|
|
|
|
By default, the input grammar is read from `stdin` and the generated code is printed to `stdout`. You may save it in a file using the `-o` flag.
|
|
|
|
## Example
|
|
|
|
Given the following grammar:
|
|
|
|
```
|
|
{
|
|
// part of the initializer code block omitted for brevity
|
|
|
|
var ops = map[string]func(int, int) int {
|
|
"+": func(l, r int) int {
|
|
return l + r
|
|
},
|
|
"-": func(l, r int) int {
|
|
return l - r
|
|
},
|
|
"*": func(l, r int) int {
|
|
return l * r
|
|
},
|
|
"/": func(l, r int) int {
|
|
return l / r
|
|
},
|
|
}
|
|
|
|
func toAnySlice(v any) []any {
|
|
if v == nil {
|
|
return nil
|
|
}
|
|
return v.([]any)
|
|
}
|
|
|
|
func eval(first, rest any) int {
|
|
l := first.(int)
|
|
restSl := toAnySlice(rest)
|
|
for _, v := range restSl {
|
|
restExpr := toAnySlice(v)
|
|
r := restExpr[3].(int)
|
|
op := restExpr[1].(string)
|
|
l = ops[op](l, r)
|
|
}
|
|
return l
|
|
}
|
|
}
|
|
|
|
|
|
Input <- expr:Expr EOF {
|
|
return expr, nil
|
|
}
|
|
|
|
Expr <- _ first:Term rest:( _ AddOp _ Term )* _ {
|
|
return eval(first, rest), nil
|
|
}
|
|
|
|
Term <- first:Factor rest:( _ MulOp _ Factor )* {
|
|
return eval(first, rest), nil
|
|
}
|
|
|
|
Factor <- '(' expr:Expr ')' {
|
|
return expr, nil
|
|
} / integer:Integer {
|
|
return integer, nil
|
|
}
|
|
|
|
AddOp <- ( '+' / '-' ) {
|
|
return string(c.text), nil
|
|
}
|
|
|
|
MulOp <- ( '*' / '/' ) {
|
|
return string(c.text), nil
|
|
}
|
|
|
|
Integer <- '-'? [0-9]+ {
|
|
return strconv.Atoi(string(c.text))
|
|
}
|
|
|
|
_ "whitespace" <- [ \n\t\r]*
|
|
|
|
EOF <- !.
|
|
```
|
|
|
|
The generated parser can parse simple arithmetic operations, e.g.:
|
|
|
|
```
|
|
18 + 3 - 27 * (-18 / -3)
|
|
|
|
=> -141
|
|
```
|
|
|
|
More examples can be found in the `examples/` subdirectory.
|
|
|
|
See the [package documentation][3] for detailed usage.
|
|
|
|
## Contributing
|
|
|
|
See the CONTRIBUTING.md file.
|
|
|
|
## License
|
|
|
|
The [BSD 3-Clause license][4]. See the LICENSE file.
|
|
|
|
[0]: http://en.wikipedia.org/wiki/Parsing_expression_grammar
|
|
[1]: http://pegjs.org/
|
|
[2]: http://www.codeproject.com/Articles/29713/Parsing-Expression-Grammar-Support-for-C-Part
|
|
[3]: https://pkg.go.dev/github.com/mna/pigeon
|
|
[4]: http://opensource.org/licenses/BSD-3-Clause
|
|
[5]: https://github.com/breml
|
|
[6]: https://github.com/mna
|