%{
package main
import (
"fmt"
"io"
"os"
)
type Pipe struct {
First Expr
Second Expr
}
type Multi struct {
Cmds []Expr
Out Expr
}
type Expr struct {
Pipe *Pipe
Cmd []string
Multi *Multi
}
var Exp Expr
%}
%union {
expr Expr
exprs []Expr
filter []string
rune rune
str string
}
%token <rune> '|'
%token <rune> '>'
%token <rune> '('
%token <rune> ')'
%token <rune> '&'
%token <str> STRING
%type <expr> expr
%type <expr> filter
%type <expr> multi
%type <exprs> join
%%
top:
expr {
Exp = $1
}
expr:
filter
| multi
| expr '|' filter {
$$ = Expr{
Pipe: &Pipe{
First: $1,
Second: $3,
},
}
}
| expr '|' multi {
$$ = Expr{
Pipe: &Pipe{
First: $1,
Second: $3,
},
}
}
multi:
join '>' filter {
$$ = Expr{
Multi: &Multi{
Cmds: $1,
Out: $3,
},
}
}
join:
filter {
$$ = []Expr{$1}
}
| join '&' filter {
$$ = append($1, $3)
}
filter:
STRING {
$$ = Expr{Cmd: []string{$1}}
}
| filter STRING {
$$.Cmd = append($1.Cmd, $2)
}
| '(' expr ')' {
$$ = $2
}
%%
type yyLex struct {
Toks []string
index int
Err io.Writer
}
func (x *yyLex) Lex(yylval *yySymType) int {
if len(x.Toks) == 0 {
return 0
}
if len(x.Toks[0]) == 0 {
goto str
} else if len(x.Toks[0]) <= x.index {
x.Toks = x.Toks[1:]
x.index = 0
return x.Lex(yylval)
}
switch x.Toks[0][x.index] {
case '|':
fallthrough
case '>':
fallthrough
case '(':
fallthrough
case ')':
fallthrough
case '&':
ret := x.Toks[0][x.index]
x.index++
return int(ret)
}
str:
yylval.str = x.Toks[0][x.index:]
x.Toks = x.Toks[1:]
return STRING
}
func (x *yyLex) Error(s string) {
fmt.Fprintln(x.Err, "parse: " + s)
os.Exit(1)
}