Last active
August 22, 2019 19:00
-
-
Save dreampuf/5ae11ab5a4701290fc35539460d8824d to your computer and use it in GitHub Desktop.
hostlist generate by goyacc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%{ | |
package main | |
import( | |
"fmt" | |
"bufio" | |
"os" | |
"strconv" | |
"unicode" | |
"unicode/utf8" | |
) | |
const( | |
Debug = 4 | |
ErrorVerbose = true | |
) | |
type LexerStatus int | |
const ( | |
INITIAL_STATUS LexerStatus = iota | |
IN_INT_PART_STATUS | |
DOT_STATUS | |
IN_FRAC_PART_STATUS | |
) | |
type GoCalcLex struct { | |
Pos int | |
Status LexerStatus | |
Input []byte | |
} | |
%} | |
%union { | |
int_value int | |
float_value float64 | |
} | |
%token <float_value> DOUBLE_LITERAL | |
%token ADD SUB MUL DIV CR LP RP | |
%type <float_value> expression term primary_expression | |
%% | |
line_list | |
: line | |
| line_list line | |
; | |
line | |
: expression CR | |
{ | |
fmt.Printf(">>%1f\n", $1); | |
} | |
; | |
expression | |
: term | |
| expression ADD term | |
{ | |
$$ = $1 + $3; | |
} | |
| expression SUB term | |
{ | |
$$ = $1 - $3; | |
} | |
; | |
term | |
: primary_expression | |
| term MUL primary_expression | |
{ | |
$$ = $1 * $3; | |
} | |
| term DIV primary_expression | |
{ | |
$$ = $1 / $3; | |
} | |
; | |
primary_expression | |
: DOUBLE_LITERAL | |
| LP expression RP | |
{ | |
$$ = $2; | |
} | |
| SUB primary_expression | |
{ | |
$$ = -$2; | |
} | |
; | |
%% | |
func (l *GoCalcLex) Lex(lval *yySymType) int { | |
var Str []rune | |
l.Status = INITIAL_STATUS | |
for l.Pos < len(l.Input) { | |
r, n := utf8.DecodeRune(l.Input[l.Pos:]) | |
if (l.Status == IN_INT_PART_STATUS || l.Status == IN_FRAC_PART_STATUS) && | |
!unicode.IsDigit(r) && r != '.' { | |
lval.float_value, _ = strconv.ParseFloat(string(Str), 64) | |
return DOUBLE_LITERAL | |
} | |
if unicode.IsSpace(r) { | |
l.Pos = l.Pos + n | |
if r == '\n' || r == '\r' { | |
return CR | |
} | |
continue | |
} | |
Str = append(Str, r) | |
l.Pos = l.Pos + n | |
switch { | |
case r == '+': | |
return ADD | |
case r == '-': | |
return SUB | |
case r == '*': | |
return MUL | |
case r == '/': | |
return DIV | |
case r == '(': | |
return LP | |
case r == ')': | |
return RP | |
case r == '.': | |
if l.Status == IN_INT_PART_STATUS { | |
l.Status = DOT_STATUS | |
} else { | |
fmt.Println("syntax error in dot") | |
os.Exit(1) | |
} | |
case unicode.IsDigit(r): | |
if l.Status == INITIAL_STATUS { | |
l.Status = IN_INT_PART_STATUS | |
} else if l.Status == DOT_STATUS { | |
l.Status = IN_FRAC_PART_STATUS | |
} | |
default: | |
fmt.Println("unknow input type %s", string(r)) | |
os.Exit(1) | |
} | |
} | |
return 0 | |
} | |
func (l *GoCalcLex) Error(s string) { | |
fmt.Printf("syntax error: %s\n", s) | |
} | |
func main(){ | |
scanner := bufio.NewScanner(os.Stdin) | |
for scanner.Scan(){ | |
text := scanner.Text() | |
text = fmt.Sprintf("%s\n", text) | |
yyParse(&GoCalcLex{Input: []byte(text)}) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%{ | |
package main | |
import ( | |
"text/scanner" | |
"strconv" | |
"strings" | |
"fmt" | |
"reflect" | |
) | |
type Expression interface{} | |
type ParenExpr struct { | |
SubExpr Expression | |
} | |
type Token struct { | |
token int | |
literal string | |
} | |
type NumExpr struct { | |
literal string | |
} | |
type ChainExpr struct { | |
current Expression | |
next Expression | |
} | |
type IdentifyExpr struct { | |
token Token | |
} | |
type PairExpr struct { | |
left Expression | |
right Expression | |
} | |
type RangeExpr struct { | |
start NumExpr | |
end NumExpr | |
} | |
type NotExpr struct { | |
supset Expression | |
exclusive Expression | |
} | |
type MultiExpr struct { | |
current Expression | |
next Expression | |
} | |
%} | |
%union{ | |
token Token | |
expr Expression | |
} | |
// hostname[111-123!120,324]postfix,hostname2[1-10,134]postfix2,hostname[1-10!(2,3,4)]postfix | |
// hostname '[' 111 '-' 123 '!' 123 ',' 324 ']' postfix | |
%type<expr> program | |
%type<expr> expr range | |
%token<token> IDENTIFY NUMBER OPENNING_BRACKET CLOSING_BRACKET COMMA DASH OPENNING_PARENTHESIS CLOSING_PARENTHESIS EXCLAMATION | |
%left IDENTIFY | |
%left NUMBER | |
%left OPENNING_BRACKET CLOSING_BRACKET | |
%left EXCLAMATION | |
%left MINUS | |
%left COMMA | |
%left OPENNING_PARENTHESIS CLOSING_PARENTHESIS | |
%% | |
program | |
: expr | |
{ | |
$$ = ParenExpr{SubExpr: $1} | |
yylex.(*Lexer).result = $$ | |
} | |
| program COMMA expr | |
{ | |
$$ = MultiExpr{current: $1, next: $3} | |
yylex.(*Lexer).result = $$ | |
} | |
; | |
expr | |
: IDENTIFY | |
{ | |
$$ = IdentifyExpr{token: $1} | |
} | |
| OPENNING_BRACKET range CLOSING_BRACKET | |
{ | |
$$ = ParenExpr{SubExpr: $2} | |
} | |
| expr IDENTIFY | |
{ | |
$$ = ChainExpr{current: $1, next: IdentifyExpr{token: $2}} | |
} | |
| expr OPENNING_BRACKET range CLOSING_BRACKET | |
{ | |
$$ = ChainExpr{current: $1, next: ParenExpr{SubExpr: $3}} | |
} | |
; | |
range | |
: range COMMA range | |
{ | |
$$ = PairExpr{left: $1, right: $3} | |
} | |
| NUMBER | |
{ | |
$$ = NumExpr{literal: $1.literal} | |
} | |
| range EXCLAMATION range | |
{ | |
$$ = NotExpr{supset: $1, exclusive: $3} | |
} | |
| NUMBER DASH NUMBER | |
{ | |
$$ = RangeExpr{start: NumExpr{literal: $1.literal}, end: NumExpr{literal: $3.literal}} | |
} | |
| OPENNING_PARENTHESIS range CLOSING_PARENTHESIS | |
{ | |
$$ = ParenExpr{SubExpr: $2} | |
} | |
; | |
%% | |
type Lexer struct { | |
scanner.Scanner | |
result Expression | |
} | |
func (l *Lexer) Lex(lval *yySymType) int { | |
token := l.Scan() | |
lit := l.TokenText() | |
//fmt.Printf("token: '%d' '%s'\n", token, lit) | |
tok := int(token) | |
switch tok { | |
case scanner.Int: | |
tok = NUMBER | |
default: | |
switch lit { | |
case "[": | |
tok = OPENNING_BRACKET | |
case "]": | |
tok = CLOSING_BRACKET | |
case ",": | |
tok = COMMA | |
case "-": | |
tok = DASH | |
case "!": | |
tok = EXCLAMATION | |
case "(": | |
tok = OPENNING_PARENTHESIS | |
case ")": | |
tok = CLOSING_PARENTHESIS | |
case "": | |
tok = 0 | |
default: | |
tok = IDENTIFY | |
} | |
} | |
lval.token = Token{token: tok, literal: lit} | |
return tok | |
} | |
func (l *Lexer) Error(e string) { | |
fmt.Println(e) | |
} | |
func combineLists(lists ...[]string) []string { | |
tlist := []string{""} | |
for _, ls := range lists { | |
nlist := []string{} | |
if len(ls) == 0 { | |
nlist = tlist | |
} | |
for _, pre := range tlist { | |
for _, i := range ls { | |
nlist = append(nlist, pre + i) | |
} | |
} | |
tlist = nlist | |
} | |
return tlist | |
} | |
func subSet(a, b []string) []string { | |
t := []string{} | |
outter: | |
for _, i := range a { | |
for _, ii := range b { | |
if i == ii { | |
continue outter | |
} | |
} | |
t = append(t, i) | |
} | |
return t | |
} | |
func generateRange(start, end int, padding int) []string { | |
t := []string{} | |
tmp := fmt.Sprintf("%%0%dd", padding) | |
for i := start; i <= end; i ++ { | |
t = append(t, fmt.Sprintf(tmp, i)) | |
} | |
return t | |
} | |
func EvalN(e Expression) int { | |
switch t := e.(type) { | |
case NumExpr: | |
num, _ := strconv.Atoi(t.literal) | |
return num | |
} | |
return 0 | |
} | |
func Eval(e Expression) []string { | |
if e == nil { | |
return []string{} | |
} | |
//fmt.Printf("eval %s: %v\n", reflect.TypeOf(e), e) | |
switch t := e.(type) { | |
case ParenExpr: | |
return Eval(t.SubExpr) | |
case ChainExpr: | |
cur := Eval(t.current) | |
next := Eval(t.next) | |
return combineLists(cur, next) | |
case IdentifyExpr: | |
return []string{ t.token.literal } | |
case NotExpr: | |
supset := Eval(t.supset) | |
exclusive := Eval(t.exclusive) | |
return subSet(supset, exclusive) | |
case RangeExpr: | |
start := EvalN(t.start) | |
end := EvalN(t.end) | |
return generateRange(start, end, len(t.start.literal)) | |
case PairExpr: | |
left := Eval(t.left) | |
right := Eval(t.right) | |
return append(left, right...) | |
case NumExpr: | |
return []string{ t.literal } | |
case MultiExpr: | |
//fmt.Printf("cur: %v, next: %v\n", Eval(t.current), Eval(t.next)) | |
return append(Eval(t.current), Eval(t.next)...) | |
default: | |
fmt.Printf("unsuported %s[%+v]\n", reflect.TypeOf(t), t) | |
} | |
return []string{} | |
} | |
func Parse(exp string) []string { | |
//yyDebug = 4 | |
//yyErrorVerbose = true | |
l := new(Lexer) | |
l.Init(strings.NewReader(exp)) | |
yyParse(l) | |
//fmt.Printf("%s\n%+v\n\n", exp, l.result) | |
return Eval(l.result) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment