Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

https://github.com/mna/pigeon

Command pigeon generates parsers in Go from a PEG grammar.
https://github.com/mna/pigeon

parser parser-generator peg

Last synced: about 2 months ago
JSON representation

Command pigeon generates parsers in Go from a PEG grammar.

Lists

README

        

# pigeon - a PEG parser generator for Go

[![Go Reference](https://pkg.go.dev/badge/github.com/mna/pigeon.svg)](https://pkg.go.dev/github.com/mna/pigeon)
[![Test Status](https://github.com/mna/pigeon/workflows/Go%20Matrix/badge.svg)](https://github.com/mna/pigeon/actions?query=workflow%3AGo%20Matrix)
[![GoReportCard](https://goreportcard.com/badge/github.com/mna/pigeon)](https://goreportcard.com/report/github.com/mna/pigeon)
[![Software License](https://img.shields.io/badge/license-BSD-blue.svg)](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