diff --git a/main.go b/main.go new file mode 100644 index 0000000..1dd7df7 --- /dev/null +++ b/main.go @@ -0,0 +1,11 @@ +package main + +import ( + "github.com/myrp556/yacc_parse/parser" +) + +func main() { + lex := parser.NewLex("SELECT * FROM table1, table2 WHERE a>1 and (b<2 OR c=1)") + statements := parser.Parse(lex) + parser.Travel(statements) +} diff --git a/parser/lex.go b/parser/lex.go new file mode 100644 index 0000000..ec7c26f --- /dev/null +++ b/parser/lex.go @@ -0,0 +1,49 @@ +package parser + +import ( + "log" + "strconv" +) + +type lex struct { + input string + scanner *Scanner + Query Query +} + +func NewLex(input string) *lex { + return &lex{ + input: input, + scanner: newScanner(input), + } +} + +func (l *lex) Lex(lval *yySymType) int { + typ, str := l.scanner.nextToken() + log.Println(typ, str) + + switch typ { + case 0: + return 0 + case INTEGER: + lval.int64, _ = strconv.ParseInt(str, 10, 64) + case FLOAT: + lval.float64, _ = strconv.ParseFloat(str, 64) + //case STRING, NAME: + // lex.str = str + case EQ, NEQ, LT, LTE, GT, GTE, AND, OR, ADD, DEC: + lval.int = typ + } + lval.str = str + + return typ +} + +func (l *lex) Error(err string) { + log.Fatal(err) +} + +func Parse(l *lex) Statements { + yyParse(l) + return l.Query.Statements +} diff --git a/parser/node.go b/parser/node.go new file mode 100644 index 0000000..d0bbaf1 --- /dev/null +++ b/parser/node.go @@ -0,0 +1,136 @@ +package parser + +import ( + "strconv" + "fmt" +) + +type ExprNodeType int + +const ( + Unknown ExprNodeType = 0 + BinaryNode ExprNodeType = 1 + FieldNode ExprNodeType = 2 + IntegerNode ExprNodeType = 3 + FloatNode ExprNodeType = 4 + StringNode ExprNodeType = 5 +) + +type Statements []Statement +type Fields []*Field +type Sources []*Source + +type Field struct { + Name string +} + +type Source struct { + Name string +} + +type Statement interface { + stmt() + travel() +} + +type Query struct { + Statements Statements +} + +type ExprNode struct { + Type ExprNodeType + Left *ExprNode + Right *ExprNode + + FloVal float64 + IntVal int64 + StrVal string + Name string + Op int +} + +func Travel(stmts Statements) { + for _, stmt := range stmts { + stmt.travel() + } +} + +func (fields Fields) str() string { + str := "" + for i, field := range fields { + if i > 0 { + str = str + ", " + } + + str = str + field.str() + } + return str +} + +func (field *Field) str() string { + return field.Name +} + +func (sources Sources) str() string { + str := "" + for i, source := range sources { + if i > 0 { + str = str + ", " + } + str = str + source.str() + } + return str +} + +func (source *Source) str() string { + return source.Name +} + +func (node *ExprNode) str() string { + switch node.Type { + case FieldNode: + return node.Name + case StringNode: + return node.StrVal + case IntegerNode: + return strconv.FormatInt(node.IntVal, 10) + case FloatNode: + return strconv.FormatFloat(node.FloVal, 'f', -1, 64) + case BinaryNode: + return fmt.Sprintf("(%s %s %s)", node.Left.str(), opToStr(node.Op), node.Right.str()) + } + + return "?" +} + +func opToStr(op int) string { + switch op { + case EQ: + return "=" + case NEQ: + return "<>" + case GT: + return ">" + case GTE: + return ">=" + case LT: + return "<" + case LTE: + return "<=" + case AND: + return "AND" + case OR: + return "OR" + case ADD: + return "+" + case DEC: + return "-" + case STAR: + return "*" + case COMMA: + return "," + case SEMICOLON: + return ";" + } + return "" +} diff --git a/parser/parse.y b/parser/parse.y new file mode 100644 index 0000000..2ab141f --- /dev/null +++ b/parser/parse.y @@ -0,0 +1,177 @@ +%{ +package parser + +import ( + //"fmt" +) + +func addStatement(yylex yyLexer, stmt Statement) { + yylex.(*lex).Query.Statements = append(yylex.(*lex).Query.Statements, stmt) +} + +%} + +%union { + stmt Statement + stmts Statements + selectStmt *SelectStatement + + str string + query Query + field *Field + fields Fields + source *Source + sources Sources + + int int + int64 int64 + float64 float64 + bool bool + + expr *ExprNode +} + +%token SELECT FROM WHERE AS GROUP BY ORDER LIMIT CREATE +%token UPDATE INSERT INTO DELETE +%token STAR +%token EQ NEQ LT LTE GT GTE +%token LEFTC, RIGHTC +%token NAME +%token INTEGER +%token FLOAT +%token STRING +%token COMMA SEMICOLON + +%left OR +%left AND +%left ADD DEC +%left TIME DIV MOD + +%type QUERIES +%type STATEMENT +%type SELECT_STATEMENT +%type FIELD +%type FIELDS +%type SOURCE +%type SOURCES +%type CONDITION WHERE_CONDITION +%type CONDITION_VAR +%type OPERATOR + +//%start main + +%% + +QUERIES: + STATEMENT { + addStatement(yylex, $1) + }| + STATEMENT SEMICOLON { + addStatement(yylex, $1) + }| + STATEMENT SEMICOLON QUERIES { + addStatement(yylex, $1) + } + +STATEMENT: + SELECT_STATEMENT { + $$ = $1 + } + +SELECT_STATEMENT: + SELECT FIELDS FROM SOURCES WHERE_CONDITION { + sele := &SelectStatement{ + Fields: $2, + Sources: $4, + WhereCondition: $5, + } + + $$ = sele + } + +FIELDS: + FIELD { + $$ = []*Field{$1} + }| + FIELD COMMA FIELDS { + $$ = append($3, $1) + } + +FIELD: + NAME { + $$ = &Field{Name: $1} + }| + STAR { + $$ = &Field{Name: $1} + } + +SOURCES: + SOURCE { + $$ = []*Source{$1} + }| + SOURCE COMMA SOURCES { + $$ = append($3, $1) + } + +SOURCE: + NAME { + $$ = &Source{Name: $1} + } + +WHERE_CONDITION: + WHERE CONDITION { + $$ = $2 + }| + { + $$ = nil + } + +CONDITION: + LEFTC CONDITION RIGHTC { + $$ = $2 + }| + CONDITION_VAR OPERATOR CONDITION_VAR { + $$ = &ExprNode{Type: BinaryNode, Left: $1, Op: $2, Right: $3} + }| + CONDITION AND CONDITION { + $$ = &ExprNode{Type: BinaryNode, Left: $1, Op: $2, Right: $3} + }| + CONDITION OR CONDITION { + $$ = &ExprNode{Type: BinaryNode, Left: $1, Op: $2, Right: $3} + } + +OPERATOR: + EQ { + $$ = $1 + }| + NEQ { + $$ = $1 + }| + LT { + $$ = $1 + }| + LTE { + $$ = $1 + }| + GT { + $$ = $1 + }| + GTE { + $$ = $1 + } + +CONDITION_VAR: + NAME { + $$ = &ExprNode{Type: FieldNode, Name: $1} + }| + STRING { + $$ = &ExprNode{Type: StringNode, StrVal: $1} + }| + INTEGER { + $$ = &ExprNode{Type: IntegerNode, IntVal: $1} + }| + FLOAT { + $$ = &ExprNode{Type: FloatNode, FloVal: $1} + } + +%% diff --git a/parser/scanner.go b/parser/scanner.go new file mode 100644 index 0000000..5936f3b --- /dev/null +++ b/parser/scanner.go @@ -0,0 +1,252 @@ +package parser + +import ( + "strings" + "bytes" + "log" +) + +const ( + UNKNOWN_TYPE int = 0 +) + +func newScanner(input string) *Scanner { + log.Println("new scanner", input) + return &Scanner{ + pos: 0, + query: input, + } +} + +type Scanner struct { + pos int + query string +} + +func (scanner *Scanner) nextToken() (int, string) { + var ch rune +scan: + ch, eof := scanner.popCh() + if eof { + return 0, "" + } + + switch { + case isSpace(ch): + scanner.readSpace() + goto scan + + case ch=='.' || isDigit(ch): + scanner.unpopCh() + return scanner.readNumber() + + case ch=='\'' || ch=='"': + scanner.unpopCh() + return scanner.readString() + + case ch=='+': + return ADD, "+" + + case ch=='-': + /* + nextCh, _ := scanner.nextCh() + if nextCh=='.' || isDigit(nextCh) { + scanner.unpopCh() + return scanner.readNumber() + } + */ + return DEC, "-" + + case ch=='*': + return STAR, "*" + + case ch=='<': + nextCh, _ := scanner.nextCh() + if nextCh == '=' { + scanner.popCh() + return LTE, "<=" + } else { + if nextCh == '>' { + scanner.popCh() + return NEQ, "<>" + } + } + return LT, "<" + + case ch=='>': + nextCh, _ := scanner.nextCh() + if nextCh == '=' { + scanner.popCh() + return GTE, ">=" + } + return GT, ">" + + case ch=='=': + return EQ, "=" + + case ch=='(': + return LEFTC, "(" + + case ch==')': + return RIGHTC, ")" + + case ch==';': + return SEMICOLON, ";" + + case ch==',': + return COMMA, "," + + default: + scanner.unpopCh() + return scanner.readToken() + } + +} + +func (scanner *Scanner) popCh() (rune, bool) { + if scanner.pos < len(scanner.query) { + ch := rune(scanner.query[scanner.pos]) + scanner.pos++ + return ch, false + } + return rune(' '), true +} + +func (scanner *Scanner) nextCh() (rune, bool) { + if scanner.pos < len(scanner.query) { + return rune(scanner.query[scanner.pos]), false + } + return rune(' '), true +} + +func (scanner *Scanner) unpopCh() { + scanner.pos -- +} + +func (scanner *Scanner) readSpace() { + for scanner.pos < len(scanner.query) { + ch, eof := scanner.nextCh() + if !eof && isSpace(ch) { + scanner.popCh() + } else { + break + } + } +} + +func (scanner *Scanner) readNumber() (int, string) { + typ := INTEGER + var buf bytes.Buffer + + ch, eof := scanner.nextCh() + if !eof && ch=='-' { + scanner.popCh() + buf.WriteRune(ch) + } + for scanner.pos < len(scanner.query) { + ch, eof := scanner.nextCh() + if eof || isSpace(ch) { + break + } + if !eof && !isDigit(ch) && ch!='.' { + break + } + if ch == '.' { + typ = FLOAT + } + scanner.popCh() + buf.WriteRune(ch) + } + + return typ, string(buf.Bytes()) +} + +func (scanner *Scanner) readString() (int, string) { + ch0, eof := scanner.nextCh() + if eof || (ch0!='\'' && ch0!='"') { + return UNKNOWN_TYPE, "" + } + + var buf bytes.Buffer + scanner.popCh() + for scanner.pos < len(scanner.query) { + ch, eof := scanner.popCh() + if ch == ch0 { + return STRING, string(buf.Bytes()) + } else { + if eof { + return UNKNOWN_TYPE, string(buf.Bytes()) + } else { + buf.WriteRune(ch) + } + } + } + + return UNKNOWN_TYPE, string(buf.Bytes()) +} + +func (scanner *Scanner) readToken() (int, string) { + var buf bytes.Buffer + for scanner.pos < len(scanner.query) { + ch, eof := scanner.popCh() + if eof || isSpace(ch) { + break + } + if !eof && !isLetter(ch) && !isDigit(ch) && ch!='_' { + scanner.unpopCh() + break + } + buf.WriteRune(ch) + } + + str := string(buf.Bytes()) + upper := strings.ToUpper(str) + switch upper { + case "SELECT": + return SELECT, upper + case "FROM": + return FROM, upper + case "WHERE": + return WHERE, upper + case "AS": + return AS, upper + case "GROUP": + return GROUP, upper + case "BY": + return BY, upper + case "ORDER": + return ORDER, upper + case "LIMIT": + return LIMIT, upper + case "CREATE": + return CREATE, upper + case "UPDATE": + return UPDATE, upper + case "INSERT": + return INSERT, upper + case "INTO": + return INTO, upper + case "DELETE": + return DELETE, upper + case "AND": + return AND, upper + case "OR": + return OR, upper + } + + return NAME, str +} + +func isSpace(ch rune) bool { + return ch==' ' || ch =='\t' || ch == '\n' +} + +func isDigit(ch rune) bool { + return ch>='0' && ch<='9' +} + +func isLetter(ch rune) bool { + return ('a'<=ch&&ch<='z') || ('A'<=ch&&ch<='Z') +} + + diff --git a/parser/select.go b/parser/select.go new file mode 100644 index 0000000..dcca9dc --- /dev/null +++ b/parser/select.go @@ -0,0 +1,24 @@ +package parser + +import ( + "log" +) + +func (*SelectStatement) stmt() {} + +type SelectStatement struct { + Fields Fields + Sources Sources + WhereCondition *ExprNode +} + +func (stmt *SelectStatement) travel() { + str := "SELECT " + stmt.Fields.str() + " FROM " + stmt.Sources.str() + if stmt.WhereCondition != nil { + str = str + " WHERE " + stmt.WhereCondition.str() + } + + log.Println(str) +} + + diff --git a/parser/y.go b/parser/y.go new file mode 100644 index 0000000..9843bb9 --- /dev/null +++ b/parser/y.go @@ -0,0 +1,640 @@ +// Code generated by goyacc - DO NOT EDIT. + +package parser + +import __yyfmt__ "fmt" + +import ( +//"fmt" +) + +func addStatement(yylex yyLexer, stmt Statement) { + yylex.(*lex).Query.Statements = append(yylex.(*lex).Query.Statements, stmt) +} + +type yySymType struct { + yys int + stmt Statement + stmts Statements + selectStmt *SelectStatement + + str string + query Query + field *Field + fields Fields + source *Source + sources Sources + + int int + int64 int64 + float64 float64 + bool bool + + expr *ExprNode +} + +type yyXError struct { + state, xsym int +} + +const ( + yyDefault = 57381 + yyEofCode = 57344 + ADD = 57376 + AND = 57375 + AS = 57349 + BY = 57351 + COMMA = 57372 + CREATE = 57354 + DEC = 57377 + DELETE = 57358 + DIV = 57379 + EQ = 57360 + FLOAT = 57370 + FROM = 57347 + GROUP = 57350 + GT = 57364 + GTE = 57365 + INSERT = 57356 + INTEGER = 57369 + INTO = 57357 + LEFTC = 57366 + LIMIT = 57353 + LT = 57362 + LTE = 57363 + MOD = 57380 + NAME = 57368 + NEQ = 57361 + OR = 57374 + ORDER = 57352 + RIGHTC = 57367 + SELECT = 57346 + SEMICOLON = 57373 + STAR = 57359 + STRING = 57371 + TIME = 57378 + UPDATE = 57355 + WHERE = 57348 + yyErrCode = 57345 + + yyMaxDepth = 200 + yyTabOfs = -29 +) + +var ( + yyPrec = map[int]int{ + OR: 0, + AND: 1, + ADD: 2, + DEC: 2, + TIME: 3, + DIV: 3, + MOD: 3, + } + + yyXLAT = map[int]int{ + 57344: 0, // $end (19x) + 57373: 1, // SEMICOLON (16x) + 57368: 2, // NAME (15x) + 57370: 3, // FLOAT (11x) + 57369: 4, // INTEGER (11x) + 57371: 5, // STRING (11x) + 57375: 6, // AND (10x) + 57374: 7, // OR (10x) + 57367: 8, // RIGHTC (9x) + 57372: 9, // COMMA (5x) + 57383: 10, // CONDITION_VAR (5x) + 57360: 11, // EQ (5x) + 57347: 12, // FROM (5x) + 57364: 13, // GT (5x) + 57365: 14, // GTE (5x) + 57362: 15, // LT (5x) + 57363: 16, // LTE (5x) + 57361: 17, // NEQ (5x) + 57382: 18, // CONDITION (4x) + 57366: 19, // LEFTC (4x) + 57348: 20, // WHERE (4x) + 57384: 21, // FIELD (2x) + 57385: 22, // FIELDS (2x) + 57387: 23, // QUERIES (2x) + 57346: 24, // SELECT (2x) + 57388: 25, // SELECT_STATEMENT (2x) + 57389: 26, // SOURCE (2x) + 57390: 27, // SOURCES (2x) + 57359: 28, // STAR (2x) + 57391: 29, // STATEMENT (2x) + 57386: 30, // OPERATOR (1x) + 57392: 31, // WHERE_CONDITION (1x) + 57381: 32, // $default (0x) + 57376: 33, // ADD (0x) + 57349: 34, // AS (0x) + 57351: 35, // BY (0x) + 57354: 36, // CREATE (0x) + 57377: 37, // DEC (0x) + 57358: 38, // DELETE (0x) + 57379: 39, // DIV (0x) + 57345: 40, // error (0x) + 57350: 41, // GROUP (0x) + 57356: 42, // INSERT (0x) + 57357: 43, // INTO (0x) + 57353: 44, // LIMIT (0x) + 57380: 45, // MOD (0x) + 57352: 46, // ORDER (0x) + 57378: 47, // TIME (0x) + 57355: 48, // UPDATE (0x) + } + + yySymNames = []string{ + "$end", + "SEMICOLON", + "NAME", + "FLOAT", + "INTEGER", + "STRING", + "AND", + "OR", + "RIGHTC", + "COMMA", + "CONDITION_VAR", + "EQ", + "FROM", + "GT", + "GTE", + "LT", + "LTE", + "NEQ", + "CONDITION", + "LEFTC", + "WHERE", + "FIELD", + "FIELDS", + "QUERIES", + "SELECT", + "SELECT_STATEMENT", + "SOURCE", + "SOURCES", + "STAR", + "STATEMENT", + "OPERATOR", + "WHERE_CONDITION", + "$default", + "ADD", + "AS", + "BY", + "CREATE", + "DEC", + "DELETE", + "DIV", + "error", + "GROUP", + "INSERT", + "INTO", + "LIMIT", + "MOD", + "ORDER", + "TIME", + "UPDATE", + } + + yyTokenLiteralStrings = map[int]string{} + + yyReductions = map[int]struct{ xsym, components int }{ + 0: {0, 1}, + 1: {23, 1}, + 2: {23, 2}, + 3: {23, 3}, + 4: {29, 1}, + 5: {25, 5}, + 6: {22, 1}, + 7: {22, 3}, + 8: {21, 1}, + 9: {21, 1}, + 10: {27, 1}, + 11: {27, 3}, + 12: {26, 1}, + 13: {31, 2}, + 14: {31, 0}, + 15: {18, 3}, + 16: {18, 3}, + 17: {18, 3}, + 18: {18, 3}, + 19: {30, 1}, + 20: {30, 1}, + 21: {30, 1}, + 22: {30, 1}, + 23: {30, 1}, + 24: {30, 1}, + 25: {10, 1}, + 26: {10, 1}, + 27: {10, 1}, + 28: {10, 1}, + } + + yyXErrors = map[yyXError]string{} + + yyParseTab = [42][]uint8{ + // 0 + {23: 30, 33, 32, 29: 31}, + {29}, + {28, 69}, + {25, 25}, + {2: 36, 21: 35, 34, 28: 37}, + // 5 + {12: 40}, + {9: 38, 12: 23}, + {9: 21, 12: 21}, + {9: 20, 12: 20}, + {2: 36, 21: 35, 39, 28: 37}, + // 10 + {12: 22}, + {2: 43, 26: 42, 41}, + {15, 15, 20: 47, 31: 46}, + {19, 19, 9: 44, 20: 19}, + {17, 17, 9: 17, 20: 17}, + // 15 + {2: 43, 26: 42, 45}, + {18, 18, 20: 18}, + {24, 24}, + {2: 51, 54, 53, 52, 10: 50, 18: 48, 49}, + {16, 16, 6: 65, 66}, + // 20 + {2: 51, 54, 53, 52, 10: 50, 18: 63, 49}, + {11: 56, 13: 60, 61, 58, 59, 57, 30: 55}, + {4, 4, 6: 4, 4, 4, 11: 4, 13: 4, 4, 4, 4, 4}, + {3, 3, 6: 3, 3, 3, 11: 3, 13: 3, 3, 3, 3, 3}, + {2, 2, 6: 2, 2, 2, 11: 2, 13: 2, 2, 2, 2, 2}, + // 25 + {1, 1, 6: 1, 1, 1, 11: 1, 13: 1, 1, 1, 1, 1}, + {2: 51, 54, 53, 52, 10: 62}, + {2: 10, 10, 10, 10}, + {2: 9, 9, 9, 9}, + {2: 8, 8, 8, 8}, + // 30 + {2: 7, 7, 7, 7}, + {2: 6, 6, 6, 6}, + {2: 5, 5, 5, 5}, + {13, 13, 6: 13, 13, 13}, + {6: 65, 66, 64}, + // 35 + {14, 14, 6: 14, 14, 14}, + {2: 51, 54, 53, 52, 10: 50, 18: 68, 49}, + {2: 51, 54, 53, 52, 10: 50, 18: 67, 49}, + {11, 11, 6: 65, 11, 11}, + {12, 12, 6: 12, 12, 12}, + // 40 + {27, 23: 70, 33, 32, 29: 31}, + {26}, + } +) + +var yyDebug = 0 + +type yyLexer interface { + Lex(lval *yySymType) int + Error(s string) +} + +type yyLexerEx interface { + yyLexer + Reduced(rule, state int, lval *yySymType) bool +} + +func yySymName(c int) (s string) { + x, ok := yyXLAT[c] + if ok { + return yySymNames[x] + } + + if c < 0x7f { + return __yyfmt__.Sprintf("%q", c) + } + + return __yyfmt__.Sprintf("%d", c) +} + +func yylex1(yylex yyLexer, lval *yySymType) (n int) { + n = yylex.Lex(lval) + if n <= 0 { + n = yyEofCode + } + if yyDebug >= 3 { + __yyfmt__.Printf("\nlex %s(%#x %d), lval: %+v\n", yySymName(n), n, n, lval) + } + return n +} + +func yyParse(yylex yyLexer) int { + const yyError = 40 + + yyEx, _ := yylex.(yyLexerEx) + var yyn int + var yylval yySymType + var yyVAL yySymType + yyS := make([]yySymType, 200) + + Nerrs := 0 /* number of errors */ + Errflag := 0 /* error recovery flag */ + yyerrok := func() { + if yyDebug >= 2 { + __yyfmt__.Printf("yyerrok()\n") + } + Errflag = 0 + } + _ = yyerrok + yystate := 0 + yychar := -1 + var yyxchar int + var yyshift int + yyp := -1 + goto yystack + +ret0: + return 0 + +ret1: + return 1 + +yystack: + /* put a state and value onto the stack */ + yyp++ + if yyp >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyS[yyp] = yyVAL + yyS[yyp].yys = yystate + +yynewstate: + if yychar < 0 { + yylval.yys = yystate + yychar = yylex1(yylex, &yylval) + var ok bool + if yyxchar, ok = yyXLAT[yychar]; !ok { + yyxchar = len(yySymNames) // > tab width + } + } + if yyDebug >= 4 { + var a []int + for _, v := range yyS[:yyp+1] { + a = append(a, v.yys) + } + __yyfmt__.Printf("state stack %v\n", a) + } + row := yyParseTab[yystate] + yyn = 0 + if yyxchar < len(row) { + if yyn = int(row[yyxchar]); yyn != 0 { + yyn += yyTabOfs + } + } + switch { + case yyn > 0: // shift + yychar = -1 + yyVAL = yylval + yystate = yyn + yyshift = yyn + if yyDebug >= 2 { + __yyfmt__.Printf("shift, and goto state %d\n", yystate) + } + if Errflag > 0 { + Errflag-- + } + goto yystack + case yyn < 0: // reduce + case yystate == 1: // accept + if yyDebug >= 2 { + __yyfmt__.Println("accept") + } + goto ret0 + } + + if yyn == 0 { + /* error ... attempt to resume parsing */ + switch Errflag { + case 0: /* brand new error */ + if yyDebug >= 1 { + __yyfmt__.Printf("no action for %s in state %d\n", yySymName(yychar), yystate) + } + msg, ok := yyXErrors[yyXError{yystate, yyxchar}] + if !ok { + msg, ok = yyXErrors[yyXError{yystate, -1}] + } + if !ok && yyshift != 0 { + msg, ok = yyXErrors[yyXError{yyshift, yyxchar}] + } + if !ok { + msg, ok = yyXErrors[yyXError{yyshift, -1}] + } + if yychar > 0 { + ls := yyTokenLiteralStrings[yychar] + if ls == "" { + ls = yySymName(yychar) + } + if ls != "" { + switch { + case msg == "": + msg = __yyfmt__.Sprintf("unexpected %s", ls) + default: + msg = __yyfmt__.Sprintf("unexpected %s, %s", ls, msg) + } + } + } + if msg == "" { + msg = "syntax error" + } + yylex.Error(msg) + Nerrs++ + fallthrough + + case 1, 2: /* incompletely recovered error ... try again */ + Errflag = 3 + + /* find a state where "error" is a legal shift action */ + for yyp >= 0 { + row := yyParseTab[yyS[yyp].yys] + if yyError < len(row) { + yyn = int(row[yyError]) + yyTabOfs + if yyn > 0 { // hit + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery found error shift in state %d\n", yyS[yyp].yys) + } + yystate = yyn /* simulate a shift of "error" */ + goto yystack + } + } + + /* the current p has no shift on "error", pop stack */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) + } + yyp-- + } + /* there is no state on the stack with an error shift ... abort */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery failed\n") + } + goto ret1 + + case 3: /* no shift yet; clobber input char */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery discards %s\n", yySymName(yychar)) + } + if yychar == yyEofCode { + goto ret1 + } + + yychar = -1 + goto yynewstate /* try again in the same state */ + } + } + + r := -yyn + x0 := yyReductions[r] + x, n := x0.xsym, x0.components + yypt := yyp + _ = yypt // guard against "declared and not used" + + yyp -= n + if yyp+1 >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyVAL = yyS[yyp+1] + + /* consult goto table to find next state */ + exState := yystate + yystate = int(yyParseTab[yyS[yyp].yys][x]) + yyTabOfs + /* reduction by production r */ + if yyDebug >= 2 { + __yyfmt__.Printf("reduce using rule %v (%s), and goto state %d\n", r, yySymNames[x], yystate) + } + + switch r { + case 1: + { + addStatement(yylex, yyS[yypt-0].stmt) + } + case 2: + { + addStatement(yylex, yyS[yypt-1].stmt) + } + case 3: + { + addStatement(yylex, yyS[yypt-2].stmt) + } + case 4: + { + yyVAL.stmt = yyS[yypt-0].selectStmt + } + case 5: + { + sele := &SelectStatement{ + Fields: yyS[yypt-3].fields, + Sources: yyS[yypt-1].sources, + WhereCondition: yyS[yypt-0].expr, + } + + yyVAL.selectStmt = sele + } + case 6: + { + yyVAL.fields = []*Field{yyS[yypt-0].field} + } + case 7: + { + yyVAL.fields = append(yyS[yypt-0].fields, yyS[yypt-2].field) + } + case 8: + { + yyVAL.field = &Field{Name: yyS[yypt-0].str} + } + case 9: + { + yyVAL.field = &Field{Name: yyS[yypt-0].str} + } + case 10: + { + yyVAL.sources = []*Source{yyS[yypt-0].source} + } + case 11: + { + yyVAL.sources = append(yyS[yypt-0].sources, yyS[yypt-2].source) + } + case 12: + { + yyVAL.source = &Source{Name: yyS[yypt-0].str} + } + case 13: + { + yyVAL.expr = yyS[yypt-0].expr + } + case 14: + { + yyVAL.expr = nil + } + case 15: + { + yyVAL.expr = yyS[yypt-1].expr + } + case 16: + { + yyVAL.expr = &ExprNode{Type: BinaryNode, Left: yyS[yypt-2].expr, Op: yyS[yypt-1].int, Right: yyS[yypt-0].expr} + } + case 17: + { + yyVAL.expr = &ExprNode{Type: BinaryNode, Left: yyS[yypt-2].expr, Op: yyS[yypt-1].int, Right: yyS[yypt-0].expr} + } + case 18: + { + yyVAL.expr = &ExprNode{Type: BinaryNode, Left: yyS[yypt-2].expr, Op: yyS[yypt-1].int, Right: yyS[yypt-0].expr} + } + case 19: + { + yyVAL.int = yyS[yypt-0].int + } + case 20: + { + yyVAL.int = yyS[yypt-0].int + } + case 21: + { + yyVAL.int = yyS[yypt-0].int + } + case 22: + { + yyVAL.int = yyS[yypt-0].int + } + case 23: + { + yyVAL.int = yyS[yypt-0].int + } + case 24: + { + yyVAL.int = yyS[yypt-0].int + } + case 25: + { + yyVAL.expr = &ExprNode{Type: FieldNode, Name: yyS[yypt-0].str} + } + case 26: + { + yyVAL.expr = &ExprNode{Type: StringNode, StrVal: yyS[yypt-0].str} + } + case 27: + { + yyVAL.expr = &ExprNode{Type: IntegerNode, IntVal: yyS[yypt-0].int64} + } + case 28: + { + yyVAL.expr = &ExprNode{Type: FloatNode, FloVal: yyS[yypt-0].float64} + } + + } + + if yyEx != nil && yyEx.Reduced(r, exState, &yyVAL) { + return -1 + } + goto yystack /* stack new state and value */ +} diff --git a/parser/y.output b/parser/y.output new file mode 100644 index 0000000..05dd917 --- /dev/null +++ b/parser/y.output @@ -0,0 +1,426 @@ +state 0 // + + 0 $accept: . QUERIES + + SELECT shift, and goto state 4 + + QUERIES goto state 1 + SELECT_STATEMENT goto state 3 + STATEMENT goto state 2 + +state 1 // SELECT NAME FROM NAME [$end] + + 0 $accept: QUERIES . [$end] + + $end accept + +state 2 // SELECT NAME FROM NAME [$end] + + 1 QUERIES: STATEMENT . [$end] + 2 QUERIES: STATEMENT . SEMICOLON + 3 QUERIES: STATEMENT . SEMICOLON QUERIES + + $end reduce using rule 1 (QUERIES) + SEMICOLON shift, and goto state 40 + +state 3 // SELECT NAME FROM NAME [$end] + + 4 STATEMENT: SELECT_STATEMENT . [$end, SEMICOLON] + + $end reduce using rule 4 (STATEMENT) + SEMICOLON reduce using rule 4 (STATEMENT) + +state 4 // SELECT + + 5 SELECT_STATEMENT: SELECT . FIELDS FROM SOURCES WHERE_CONDITION + + NAME shift, and goto state 7 + STAR shift, and goto state 8 + + FIELD goto state 6 + FIELDS goto state 5 + +state 5 // SELECT NAME [FROM] + + 5 SELECT_STATEMENT: SELECT FIELDS . FROM SOURCES WHERE_CONDITION + + FROM shift, and goto state 11 + +state 6 // SELECT NAME [COMMA] + + 6 FIELDS: FIELD . [FROM] + 7 FIELDS: FIELD . COMMA FIELDS + + COMMA shift, and goto state 9 + FROM reduce using rule 6 (FIELDS) + +state 7 // SELECT NAME + + 8 FIELD: NAME . [COMMA, FROM] + + COMMA reduce using rule 8 (FIELD) + FROM reduce using rule 8 (FIELD) + +state 8 // SELECT STAR + + 9 FIELD: STAR . [COMMA, FROM] + + COMMA reduce using rule 9 (FIELD) + FROM reduce using rule 9 (FIELD) + +state 9 // SELECT NAME COMMA + + 7 FIELDS: FIELD COMMA . FIELDS + + NAME shift, and goto state 7 + STAR shift, and goto state 8 + + FIELD goto state 6 + FIELDS goto state 10 + +state 10 // SELECT NAME COMMA NAME [FROM] + + 7 FIELDS: FIELD COMMA FIELDS . [FROM] + + FROM reduce using rule 7 (FIELDS) + +state 11 // SELECT NAME FROM + + 5 SELECT_STATEMENT: SELECT FIELDS FROM . SOURCES WHERE_CONDITION + + NAME shift, and goto state 14 + + SOURCE goto state 13 + SOURCES goto state 12 + +state 12 // SELECT NAME FROM NAME [$end] + + 5 SELECT_STATEMENT: SELECT FIELDS FROM SOURCES . WHERE_CONDITION + 14 WHERE_CONDITION: . [$end, SEMICOLON] + + $end reduce using rule 14 (WHERE_CONDITION) + SEMICOLON reduce using rule 14 (WHERE_CONDITION) + WHERE shift, and goto state 18 + + WHERE_CONDITION goto state 17 + +state 13 // SELECT NAME FROM NAME [$end] + + 10 SOURCES: SOURCE . [$end, SEMICOLON, WHERE] + 11 SOURCES: SOURCE . COMMA SOURCES + + $end reduce using rule 10 (SOURCES) + COMMA shift, and goto state 15 + SEMICOLON reduce using rule 10 (SOURCES) + WHERE reduce using rule 10 (SOURCES) + +state 14 // SELECT NAME FROM NAME + + 12 SOURCE: NAME . [$end, COMMA, SEMICOLON, WHERE] + + $end reduce using rule 12 (SOURCE) + COMMA reduce using rule 12 (SOURCE) + SEMICOLON reduce using rule 12 (SOURCE) + WHERE reduce using rule 12 (SOURCE) + +state 15 // SELECT NAME FROM NAME COMMA + + 11 SOURCES: SOURCE COMMA . SOURCES + + NAME shift, and goto state 14 + + SOURCE goto state 13 + SOURCES goto state 16 + +state 16 // SELECT NAME FROM NAME COMMA NAME [$end] + + 11 SOURCES: SOURCE COMMA SOURCES . [$end, SEMICOLON, WHERE] + + $end reduce using rule 11 (SOURCES) + SEMICOLON reduce using rule 11 (SOURCES) + WHERE reduce using rule 11 (SOURCES) + +state 17 // SELECT NAME FROM NAME [$end] + + 5 SELECT_STATEMENT: SELECT FIELDS FROM SOURCES WHERE_CONDITION . [$end, SEMICOLON] + + $end reduce using rule 5 (SELECT_STATEMENT) + SEMICOLON reduce using rule 5 (SELECT_STATEMENT) + +state 18 // SELECT NAME FROM NAME WHERE + + 13 WHERE_CONDITION: WHERE . CONDITION + + FLOAT shift, and goto state 25 + INTEGER shift, and goto state 24 + LEFTC shift, and goto state 20 + NAME shift, and goto state 22 + STRING shift, and goto state 23 + + CONDITION goto state 19 + CONDITION_VAR goto state 21 + +state 19 // SELECT NAME FROM NAME WHERE FLOAT EQ FLOAT [$end] + + 13 WHERE_CONDITION: WHERE CONDITION . [$end, SEMICOLON] + 17 CONDITION: CONDITION . AND CONDITION // assoc %left, prec 2 + 18 CONDITION: CONDITION . OR CONDITION // assoc %left, prec 1 + + $end reduce using rule 13 (WHERE_CONDITION) + AND shift, and goto state 36 + OR shift, and goto state 37 + SEMICOLON reduce using rule 13 (WHERE_CONDITION) + +state 20 // SELECT NAME FROM NAME WHERE LEFTC + + 15 CONDITION: LEFTC . CONDITION RIGHTC + + FLOAT shift, and goto state 25 + INTEGER shift, and goto state 24 + LEFTC shift, and goto state 20 + NAME shift, and goto state 22 + STRING shift, and goto state 23 + + CONDITION goto state 34 + CONDITION_VAR goto state 21 + +state 21 // SELECT NAME FROM NAME WHERE FLOAT [EQ] + + 16 CONDITION: CONDITION_VAR . OPERATOR CONDITION_VAR + + EQ shift, and goto state 27 + GT shift, and goto state 31 + GTE shift, and goto state 32 + LT shift, and goto state 29 + LTE shift, and goto state 30 + NEQ shift, and goto state 28 + + OPERATOR goto state 26 + +state 22 // SELECT NAME FROM NAME WHERE NAME + + 25 CONDITION_VAR: NAME . [$end, AND, EQ, GT, GTE, LT, LTE, NEQ, OR, RIGHTC, SEMICOLON] + + $end reduce using rule 25 (CONDITION_VAR) + AND reduce using rule 25 (CONDITION_VAR) + EQ reduce using rule 25 (CONDITION_VAR) + GT reduce using rule 25 (CONDITION_VAR) + GTE reduce using rule 25 (CONDITION_VAR) + LT reduce using rule 25 (CONDITION_VAR) + LTE reduce using rule 25 (CONDITION_VAR) + NEQ reduce using rule 25 (CONDITION_VAR) + OR reduce using rule 25 (CONDITION_VAR) + RIGHTC reduce using rule 25 (CONDITION_VAR) + SEMICOLON reduce using rule 25 (CONDITION_VAR) + +state 23 // SELECT NAME FROM NAME WHERE STRING + + 26 CONDITION_VAR: STRING . [$end, AND, EQ, GT, GTE, LT, LTE, NEQ, OR, RIGHTC, SEMICOLON] + + $end reduce using rule 26 (CONDITION_VAR) + AND reduce using rule 26 (CONDITION_VAR) + EQ reduce using rule 26 (CONDITION_VAR) + GT reduce using rule 26 (CONDITION_VAR) + GTE reduce using rule 26 (CONDITION_VAR) + LT reduce using rule 26 (CONDITION_VAR) + LTE reduce using rule 26 (CONDITION_VAR) + NEQ reduce using rule 26 (CONDITION_VAR) + OR reduce using rule 26 (CONDITION_VAR) + RIGHTC reduce using rule 26 (CONDITION_VAR) + SEMICOLON reduce using rule 26 (CONDITION_VAR) + +state 24 // SELECT NAME FROM NAME WHERE INTEGER + + 27 CONDITION_VAR: INTEGER . [$end, AND, EQ, GT, GTE, LT, LTE, NEQ, OR, RIGHTC, SEMICOLON] + + $end reduce using rule 27 (CONDITION_VAR) + AND reduce using rule 27 (CONDITION_VAR) + EQ reduce using rule 27 (CONDITION_VAR) + GT reduce using rule 27 (CONDITION_VAR) + GTE reduce using rule 27 (CONDITION_VAR) + LT reduce using rule 27 (CONDITION_VAR) + LTE reduce using rule 27 (CONDITION_VAR) + NEQ reduce using rule 27 (CONDITION_VAR) + OR reduce using rule 27 (CONDITION_VAR) + RIGHTC reduce using rule 27 (CONDITION_VAR) + SEMICOLON reduce using rule 27 (CONDITION_VAR) + +state 25 // SELECT NAME FROM NAME WHERE FLOAT + + 28 CONDITION_VAR: FLOAT . [$end, AND, EQ, GT, GTE, LT, LTE, NEQ, OR, RIGHTC, SEMICOLON] + + $end reduce using rule 28 (CONDITION_VAR) + AND reduce using rule 28 (CONDITION_VAR) + EQ reduce using rule 28 (CONDITION_VAR) + GT reduce using rule 28 (CONDITION_VAR) + GTE reduce using rule 28 (CONDITION_VAR) + LT reduce using rule 28 (CONDITION_VAR) + LTE reduce using rule 28 (CONDITION_VAR) + NEQ reduce using rule 28 (CONDITION_VAR) + OR reduce using rule 28 (CONDITION_VAR) + RIGHTC reduce using rule 28 (CONDITION_VAR) + SEMICOLON reduce using rule 28 (CONDITION_VAR) + +state 26 // SELECT NAME FROM NAME WHERE FLOAT EQ [FLOAT] + + 16 CONDITION: CONDITION_VAR OPERATOR . CONDITION_VAR + + FLOAT shift, and goto state 25 + INTEGER shift, and goto state 24 + NAME shift, and goto state 22 + STRING shift, and goto state 23 + + CONDITION_VAR goto state 33 + +state 27 // SELECT NAME FROM NAME WHERE FLOAT EQ + + 19 OPERATOR: EQ . [FLOAT, INTEGER, NAME, STRING] + + FLOAT reduce using rule 19 (OPERATOR) + INTEGER reduce using rule 19 (OPERATOR) + NAME reduce using rule 19 (OPERATOR) + STRING reduce using rule 19 (OPERATOR) + +state 28 // SELECT NAME FROM NAME WHERE FLOAT NEQ + + 20 OPERATOR: NEQ . [FLOAT, INTEGER, NAME, STRING] + + FLOAT reduce using rule 20 (OPERATOR) + INTEGER reduce using rule 20 (OPERATOR) + NAME reduce using rule 20 (OPERATOR) + STRING reduce using rule 20 (OPERATOR) + +state 29 // SELECT NAME FROM NAME WHERE FLOAT LT + + 21 OPERATOR: LT . [FLOAT, INTEGER, NAME, STRING] + + FLOAT reduce using rule 21 (OPERATOR) + INTEGER reduce using rule 21 (OPERATOR) + NAME reduce using rule 21 (OPERATOR) + STRING reduce using rule 21 (OPERATOR) + +state 30 // SELECT NAME FROM NAME WHERE FLOAT LTE + + 22 OPERATOR: LTE . [FLOAT, INTEGER, NAME, STRING] + + FLOAT reduce using rule 22 (OPERATOR) + INTEGER reduce using rule 22 (OPERATOR) + NAME reduce using rule 22 (OPERATOR) + STRING reduce using rule 22 (OPERATOR) + +state 31 // SELECT NAME FROM NAME WHERE FLOAT GT + + 23 OPERATOR: GT . [FLOAT, INTEGER, NAME, STRING] + + FLOAT reduce using rule 23 (OPERATOR) + INTEGER reduce using rule 23 (OPERATOR) + NAME reduce using rule 23 (OPERATOR) + STRING reduce using rule 23 (OPERATOR) + +state 32 // SELECT NAME FROM NAME WHERE FLOAT GTE + + 24 OPERATOR: GTE . [FLOAT, INTEGER, NAME, STRING] + + FLOAT reduce using rule 24 (OPERATOR) + INTEGER reduce using rule 24 (OPERATOR) + NAME reduce using rule 24 (OPERATOR) + STRING reduce using rule 24 (OPERATOR) + +state 33 // SELECT NAME FROM NAME WHERE FLOAT EQ FLOAT [$end] + + 16 CONDITION: CONDITION_VAR OPERATOR CONDITION_VAR . [$end, AND, OR, RIGHTC, SEMICOLON] + + $end reduce using rule 16 (CONDITION) + AND reduce using rule 16 (CONDITION) + OR reduce using rule 16 (CONDITION) + RIGHTC reduce using rule 16 (CONDITION) + SEMICOLON reduce using rule 16 (CONDITION) + +state 34 // SELECT NAME FROM NAME WHERE LEFTC FLOAT EQ FLOAT [AND] + + 15 CONDITION: LEFTC CONDITION . RIGHTC + 17 CONDITION: CONDITION . AND CONDITION // assoc %left, prec 2 + 18 CONDITION: CONDITION . OR CONDITION // assoc %left, prec 1 + + AND shift, and goto state 36 + OR shift, and goto state 37 + RIGHTC shift, and goto state 35 + +state 35 // SELECT NAME FROM NAME WHERE LEFTC FLOAT EQ FLOAT RIGHTC + + 15 CONDITION: LEFTC CONDITION RIGHTC . [$end, AND, OR, RIGHTC, SEMICOLON] + + $end reduce using rule 15 (CONDITION) + AND reduce using rule 15 (CONDITION) + OR reduce using rule 15 (CONDITION) + RIGHTC reduce using rule 15 (CONDITION) + SEMICOLON reduce using rule 15 (CONDITION) + +state 36 // SELECT NAME FROM NAME WHERE FLOAT EQ FLOAT AND + + 17 CONDITION: CONDITION AND . CONDITION // assoc %left, prec 2 + + FLOAT shift, and goto state 25 + INTEGER shift, and goto state 24 + LEFTC shift, and goto state 20 + NAME shift, and goto state 22 + STRING shift, and goto state 23 + + CONDITION goto state 39 + CONDITION_VAR goto state 21 + +state 37 // SELECT NAME FROM NAME WHERE FLOAT EQ FLOAT OR + + 18 CONDITION: CONDITION OR . CONDITION // assoc %left, prec 1 + + FLOAT shift, and goto state 25 + INTEGER shift, and goto state 24 + LEFTC shift, and goto state 20 + NAME shift, and goto state 22 + STRING shift, and goto state 23 + + CONDITION goto state 38 + CONDITION_VAR goto state 21 + +state 38 // SELECT NAME FROM NAME WHERE FLOAT EQ FLOAT OR FLOAT EQ FLOAT [$end] + + 17 CONDITION: CONDITION . AND CONDITION // assoc %left, prec 2 + 18 CONDITION: CONDITION . OR CONDITION // assoc %left, prec 1 + 18 CONDITION: CONDITION OR CONDITION . [$end, OR, RIGHTC, SEMICOLON] // assoc %left, prec 1 + + $end reduce using rule 18 (CONDITION) + AND shift, and goto state 36 + OR reduce using rule 18 (CONDITION) + RIGHTC reduce using rule 18 (CONDITION) + SEMICOLON reduce using rule 18 (CONDITION) + +state 39 // SELECT NAME FROM NAME WHERE FLOAT EQ FLOAT AND FLOAT EQ FLOAT [$end] + + 17 CONDITION: CONDITION . AND CONDITION // assoc %left, prec 2 + 17 CONDITION: CONDITION AND CONDITION . [$end, AND, OR, RIGHTC, SEMICOLON] // assoc %left, prec 2 + 18 CONDITION: CONDITION . OR CONDITION // assoc %left, prec 1 + + $end reduce using rule 17 (CONDITION) + AND reduce using rule 17 (CONDITION) + OR reduce using rule 17 (CONDITION) + RIGHTC reduce using rule 17 (CONDITION) + SEMICOLON reduce using rule 17 (CONDITION) + +state 40 // SELECT NAME FROM NAME SEMICOLON + + 2 QUERIES: STATEMENT SEMICOLON . [$end] + 3 QUERIES: STATEMENT SEMICOLON . QUERIES + + $end reduce using rule 2 (QUERIES) + SELECT shift, and goto state 4 + + QUERIES goto state 41 + SELECT_STATEMENT goto state 3 + STATEMENT goto state 2 + +state 41 // SELECT NAME FROM NAME SEMICOLON SELECT NAME FROM NAME [$end] + + 3 QUERIES: STATEMENT SEMICOLON QUERIES . [$end] + + $end reduce using rule 3 (QUERIES) +