diff --git a/Makefile b/Makefile index 1462dbe..3c0129a 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ all: proto grammar y2j grammar: - flexgo -G -v -o lexer.go lexer.l && goyacc -p yr -o parser.go grammar.y + flexgo -G -v -o parser/lexer.go parser/lexer.l && goyacc -p yr -o parser/parser.go parser/grammar.y hexgrammar: flexgo -G -v -o hex/hex_lexer.go hex/hex_lexer.l && goyacc -p xx -o hex/hex_parser.go hex/hex_grammar.y @@ -21,4 +21,4 @@ release: parser lexer GOOS=windows go build -o y2j.exe github.com/VirusTotal/gyp/cmd/y2j clean: - rm lexer.go parser.go yara.pb.go y.output y2j j2y + rm parser/lexer.go parser/parser.go pb/yara.pb.go y.output y2j j2y diff --git a/adapter.go b/adapter.go deleted file mode 100644 index 9328f5d..0000000 --- a/adapter.go +++ /dev/null @@ -1,105 +0,0 @@ -// adapter.go provides an adapter for a flexgo lexer to work -// with a goyacc parser - -package gyp - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - - "github.com/VirusTotal/gyp/ast" - gyperror "github.com/VirusTotal/gyp/error" -) - -func init() { - yrErrorVerbose = true -} - -// Parse parses a YARA rule from the provided input source. -func Parse(input io.Reader) (rs *ast.RuleSet, err error) { - defer func() { - if r := recover(); r != nil { - if yaraError, ok := r.(gyperror.Error); ok { - err = yaraError - } else { - err = gyperror.Error{ - Code: gyperror.UnknownError, - Message: fmt.Sprintf("%v", r), - } - } - } - }() - - lexer := &lexer{ - scanner: *NewScanner(), - ruleSet: &ast.RuleSet{ - Imports: make([]string, 0), - Rules: make([]*ast.Rule, 0), - }, - } - lexer.scanner.In = input - lexer.scanner.Out = ioutil.Discard - - if result := yrParse(lexer); result != 0 { - err = lexer.err - } - - return lexer.ruleSet, err -} - -// ParseString parses a YARA rule from the provided string. -func ParseString(s string) (*ast.RuleSet, error) { - return Parse(bytes.NewBufferString(s)) -} - -// Lexer is an adapter that fits the flexgo lexer ("Scanner") into goyacc -type lexer struct { - scanner Scanner - err gyperror.Error - ruleSet *ast.RuleSet -} - -// Lex provides the interface expected by the goyacc parser. -// It sets the context's lval pointer (defined in the lexer file) -// to the one passed as an argument so that the parser actions -// can make use of it. -func (l *lexer) Lex(lval *yrSymType) int { - l.scanner.Context.lval = lval - r := l.scanner.Lex() - if r.Error.Code != 0 { - r.Error.Line = l.scanner.Lineno - panic(r.Error) - } - return r.Token -} - -// Error satisfies the interface expected of the goyacc parser. -func (l *lexer) Error(msg string) { - l.err = gyperror.Error{ - Code: gyperror.LexicalError, - Line: l.scanner.Lineno, - Message: msg, - } -} - -// SetError sets the lexer error. The error message can be built by passing -// a format string and arguments as fmt.Sprintf. This function returns 1 as -// it's intended to by used in grammar.y as: -// return lexer.SetError(...) -// By returning 1 from the parser the parsing is aborted. -func (l *lexer) SetError(code gyperror.Code, format string, a ...interface{}) int { - l.err = gyperror.Error{ - Code: code, - Line: l.scanner.Lineno, - Message: fmt.Sprintf(format, a...), - } - return 1 -} - -// Helper function that casts a yrLexer interface to a lexer struct. This -// function is used in grammar.y. -func asLexer(l yrLexer) *lexer { - return l.(*lexer) -} diff --git a/gyp.go b/gyp.go new file mode 100644 index 0000000..51b8ad3 --- /dev/null +++ b/gyp.go @@ -0,0 +1,36 @@ +/* +Package gyp provides a pure Go parser for YARA rules. + +For example, you can parse YARA rules from a string: + ruleset, err := gyp.ParseString("rule test { condition: true }") + +Or from a io.Reader: + ruleset, err := gyp.Parse(os.Stdin) + +The rules can be written to source again: + err := ruleset.WriteSource(os.Stdout) + +Or you can iterate over the rules and inspect their attributes: + for _, rule := ruleset.Rules { + fmt.Println(rule.Identifier) + } +*/ +package gyp + +import ( + "bytes" + "io" + + "github.com/VirusTotal/gyp/ast" + "github.com/VirusTotal/gyp/parser" +) + +// Parse parses a YARA rule from the provided input source. +func Parse(input io.Reader) (rs *ast.RuleSet, err error) { + return parser.Parse(input) +} + +// ParseString parses a YARA rule from the provided string. +func ParseString(s string) (*ast.RuleSet, error) { + return Parse(bytes.NewBufferString(s)) +} diff --git a/parser_test.go b/gyp_test.go similarity index 100% rename from parser_test.go rename to gyp_test.go diff --git a/grammar.y b/parser/grammar.y similarity index 90% rename from grammar.y rename to parser/grammar.y index 8075e15..f1c87cd 100644 --- a/grammar.y +++ b/parser/grammar.y @@ -28,9 +28,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ %{ -package gyp +package parser import ( + "fmt" + "io" + "io/ioutil" "strings" "github.com/VirusTotal/gyp/ast" gyperror "github.com/VirusTotal/gyp/error" @@ -55,6 +58,93 @@ type stringModifiers struct { XorMax int32 } +// Lexer is an adapter that fits the flexgo lexer ("Scanner") into goyacc +type lexer struct { + scanner Scanner + err gyperror.Error + ruleSet *ast.RuleSet +} + +// Lex provides the interface expected by the goyacc parser. +// It sets the context's lval pointer (defined in the lexer file) +// to the one passed as an argument so that the parser actions +// can make use of it. +func (l *lexer) Lex(lval *yrSymType) int { + l.scanner.Context.lval = lval + r := l.scanner.Lex() + if r.Error.Code != 0 { + r.Error.Line = l.scanner.Lineno + panic(r.Error) + } + return r.Token +} + +// Error satisfies the interface expected of the goyacc parser. +func (l *lexer) Error(msg string) { + l.err = gyperror.Error{ + Code: gyperror.LexicalError, + Line: l.scanner.Lineno, + Message: msg, + } +} + +// setError sets the lexer error. The error message can be built by passing +// a format string and arguments as fmt.Sprintf. This function returns 1 as +// it's intended to be used by Parse as: +// return lexer.setError(...) +// By returning 1 from Parse the parsing is aborted. +func (l *lexer) setError(code gyperror.Code, format string, a ...interface{}) int { + l.err = gyperror.Error{ + Code: code, + Line: l.scanner.Lineno, + Message: fmt.Sprintf(format, a...), + } + return 1 +} + + +// Helper function that casts a yrLexer interface to a lexer struct. +func asLexer(l yrLexer) *lexer { + return l.(*lexer) +} + + +func Parse(input io.Reader) (rs *ast.RuleSet, err error) { + defer func() { + if r := recover(); r != nil { + if yaraError, ok := r.(gyperror.Error); ok { + err = yaraError + } else { + err = gyperror.Error{ + Code: gyperror.UnknownError, + Message: fmt.Sprintf("%v", r), + } + } + } + }() + + lexer := &lexer{ + scanner: *NewScanner(), + ruleSet: &ast.RuleSet{ + Imports: make([]string, 0), + Rules: make([]*ast.Rule, 0), + }, + } + lexer.scanner.In = input + lexer.scanner.Out = ioutil.Discard + + if result := yrParse(lexer); result != 0 { + err = lexer.err + } + + return lexer.ruleSet, err +} + + +func init() { + yrErrorVerbose = true +} + %} @@ -225,7 +315,7 @@ rule // Forbid duplicate rules for _, r := range lexer.ruleSet.Rules { if $3 == r.Identifier { - return lexer.SetError( + return lexer.setError( gyperror.DuplicateRuleError, `duplicate rule "%s"`, $3) } } @@ -329,7 +419,7 @@ tag_list for _, tag := range $1 { if tag == $2 { - return lexer.SetError( + return lexer.setError( gyperror.DuplicateTagError, `duplicate tag "%s"`, $2) } } @@ -449,7 +539,7 @@ string_modifiers | string_modifiers string_modifier { if $1.modifiers & $2.modifiers != 0 { - return asLexer(yrlex).SetError( + return asLexer(yrlex).setError( gyperror.DuplicateModifierError, `duplicate modifier`) } @@ -492,19 +582,19 @@ string_modifier lexer := asLexer(yrlex) if $3 < 0 { - return lexer.SetError( + return lexer.setError( gyperror.InvalidStringModifierError, "lower bound for xor range exceeded (min: 0)") } if $5 > 255 { - return lexer.SetError( + return lexer.setError( gyperror.InvalidStringModifierError, "upper bound for xor range exceeded (max: 255)") } if $3 > $5 { - return lexer.SetError( + return lexer.setError( gyperror.InvalidStringModifierError, "xor lower bound exceeds upper bound") } diff --git a/lexer.go b/parser/lexer.go similarity index 95% rename from lexer.go rename to parser/lexer.go index b74b1d8..4b451c2 100644 --- a/lexer.go +++ b/parser/lexer.go @@ -1,6 +1,6 @@ -//line lexer.go:2 -//line lexer.l:33 -package gyp +//line parser/lexer.go:2 +//line parser/lexer.l:33 +package parser import ( "fmt" @@ -51,7 +51,7 @@ type YYcontext struct { -//line lexer.go:55 +//line parser/lexer.go:55 // START OF SKELL ------------------------------------------------------ // A lexical scanner generated by flexgo @@ -452,7 +452,7 @@ var yyRuleCanMatchEol = [74]int32{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, }; -//line lexer.l:1 +//line parser/lexer.l:1 /* Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved. @@ -483,7 +483,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Lexical analyzer for YARA */ -//line lexer.l:84 +//line parser/lexer.l:84 @@ -495,7 +495,7 @@ const eof = 0 -//line lexer.go:499 +//line parser/lexer.go:499 // SKEL ---------------------------------------------------------------- const yyInitial = 0 @@ -578,10 +578,10 @@ func (yy *Scanner) Lex() YYtype { _ = yyout // [7.0] user's declarations go here ----------------------------------- -//line lexer.l:124 +//line parser/lexer.l:124 -//line lexer.go:585 +//line parser/lexer.go:585 // SKEL ---------------------------------------------------------------- for { // loops until end-of-file is reached @@ -680,7 +680,7 @@ case 1: text = append(text, yytext...) } -//line lexer.l:126 +//line parser/lexer.l:126 { return Token(_DOT_DOT_); } case 2: @@ -692,7 +692,7 @@ case 2: } -//line lexer.l:127 +//line parser/lexer.l:127 { return Token(_LT_); } case 3: @@ -704,7 +704,7 @@ case 3: } -//line lexer.l:128 +//line parser/lexer.l:128 { return Token(_GT_); } case 4: @@ -716,7 +716,7 @@ case 4: } -//line lexer.l:129 +//line parser/lexer.l:129 { return Token(_LE_); } case 5: @@ -728,7 +728,7 @@ case 5: } -//line lexer.l:130 +//line parser/lexer.l:130 { return Token(_GE_); } case 6: @@ -740,7 +740,7 @@ case 6: } -//line lexer.l:131 +//line parser/lexer.l:131 { return Token(_EQ_); } case 7: @@ -752,7 +752,7 @@ case 7: } -//line lexer.l:132 +//line parser/lexer.l:132 { return Token(_NEQ_); } case 8: @@ -764,7 +764,7 @@ case 8: } -//line lexer.l:133 +//line parser/lexer.l:133 { return Token(_SHIFT_LEFT_); } case 9: @@ -776,7 +776,7 @@ case 9: } -//line lexer.l:134 +//line parser/lexer.l:134 { return Token(_SHIFT_RIGHT_); } case 10: @@ -788,7 +788,7 @@ case 10: } -//line lexer.l:135 +//line parser/lexer.l:135 { return Token(_PRIVATE_); } case 11: @@ -800,7 +800,7 @@ case 11: } -//line lexer.l:136 +//line parser/lexer.l:136 { return Token(_GLOBAL_); } case 12: @@ -812,7 +812,7 @@ case 12: } -//line lexer.l:137 +//line parser/lexer.l:137 { return Token(_RULE_); } case 13: @@ -824,7 +824,7 @@ case 13: } -//line lexer.l:138 +//line parser/lexer.l:138 { return Token(_META_); } case 14: @@ -836,7 +836,7 @@ case 14: } -//line lexer.l:139 +//line parser/lexer.l:139 { return Token(_STRINGS_); } case 15: @@ -848,7 +848,7 @@ case 15: } -//line lexer.l:140 +//line parser/lexer.l:140 { return Token(_ASCII_); } case 16: @@ -860,7 +860,7 @@ case 16: } -//line lexer.l:141 +//line parser/lexer.l:141 { return Token(_WIDE_); } case 17: @@ -872,7 +872,7 @@ case 17: } -//line lexer.l:142 +//line parser/lexer.l:142 { return Token(_XOR_); } case 18: @@ -884,7 +884,7 @@ case 18: } -//line lexer.l:143 +//line parser/lexer.l:143 { return Token(_FULLWORD_); } case 19: @@ -896,7 +896,7 @@ case 19: } -//line lexer.l:144 +//line parser/lexer.l:144 { return Token(_NOCASE_); } case 20: @@ -908,7 +908,7 @@ case 20: } -//line lexer.l:145 +//line parser/lexer.l:145 { return Token(_CONDITION_); } case 21: @@ -920,7 +920,7 @@ case 21: } -//line lexer.l:146 +//line parser/lexer.l:146 { return Token(_TRUE_); } case 22: @@ -932,7 +932,7 @@ case 22: } -//line lexer.l:147 +//line parser/lexer.l:147 { return Token(_FALSE_); } case 23: @@ -944,7 +944,7 @@ case 23: } -//line lexer.l:148 +//line parser/lexer.l:148 { return Token(_NOT_); } case 24: @@ -956,7 +956,7 @@ case 24: } -//line lexer.l:149 +//line parser/lexer.l:149 { return Token(_AND_); } case 25: @@ -968,7 +968,7 @@ case 25: } -//line lexer.l:150 +//line parser/lexer.l:150 { return Token(_OR_); } case 26: @@ -980,7 +980,7 @@ case 26: } -//line lexer.l:151 +//line parser/lexer.l:151 { return Token(_AT_); } case 27: @@ -992,7 +992,7 @@ case 27: } -//line lexer.l:152 +//line parser/lexer.l:152 { return Token(_IN_); } case 28: @@ -1004,7 +1004,7 @@ case 28: } -//line lexer.l:153 +//line parser/lexer.l:153 { return Token(_OF_); } case 29: @@ -1016,7 +1016,7 @@ case 29: } -//line lexer.l:154 +//line parser/lexer.l:154 { return Token(_THEM_); } case 30: @@ -1028,7 +1028,7 @@ case 30: } -//line lexer.l:155 +//line parser/lexer.l:155 { return Token(_FOR_); } case 31: @@ -1040,7 +1040,7 @@ case 31: } -//line lexer.l:156 +//line parser/lexer.l:156 { return Token(_ALL_); } case 32: @@ -1052,7 +1052,7 @@ case 32: } -//line lexer.l:157 +//line parser/lexer.l:157 { return Token(_ANY_); } case 33: @@ -1064,7 +1064,7 @@ case 33: } -//line lexer.l:158 +//line parser/lexer.l:158 { return Token(_ENTRYPOINT_); } case 34: @@ -1076,7 +1076,7 @@ case 34: } -//line lexer.l:159 +//line parser/lexer.l:159 { return Token(_FILESIZE_); } case 35: @@ -1088,7 +1088,7 @@ case 35: } -//line lexer.l:160 +//line parser/lexer.l:160 { return Token(_MATCHES_); } case 36: @@ -1100,7 +1100,7 @@ case 36: } -//line lexer.l:161 +//line parser/lexer.l:161 { return Token(_CONTAINS_); } case 37: @@ -1112,7 +1112,7 @@ case 37: } -//line lexer.l:162 +//line parser/lexer.l:162 { return Token(_IMPORT_); } case 38: @@ -1124,7 +1124,7 @@ case 38: } -//line lexer.l:163 +//line parser/lexer.l:163 { return Token(_INCLUDE_); } case 39: @@ -1136,7 +1136,7 @@ case 39: } -//line lexer.l:165 +//line parser/lexer.l:165 { yy.start = 1 + 2* (comment); } case 40: @@ -1148,7 +1148,7 @@ case 40: } -//line lexer.l:166 +//line parser/lexer.l:166 { yy.start = 1 + 2* (yyInitial ); } case 41: /* rule 41 can match eol */ @@ -1161,7 +1161,7 @@ case 41: } -//line lexer.l:167 +//line parser/lexer.l:167 { /* skip comments */ } case 42: @@ -1173,7 +1173,7 @@ case 42: } -//line lexer.l:170 +//line parser/lexer.l:170 { /* skip single-line comments */ } case (yyEndOfBuffer + yyInitial + 1) : fallthrough @@ -1184,7 +1184,7 @@ case (yyEndOfBuffer + regexp + 1) : case (yyEndOfBuffer + include + 1) : fallthrough case (yyEndOfBuffer + comment + 1) : -//line lexer.l:172 +//line parser/lexer.l:172 { return Token(eof) } case 43: @@ -1196,7 +1196,7 @@ case 43: } -//line lexer.l:175 +//line parser/lexer.l:175 { yy.Context.lval.s = string(yytext) return Token(_STRING_IDENTIFIER_WITH_WILDCARD_); @@ -1211,7 +1211,7 @@ case 44: } -//line lexer.l:181 +//line parser/lexer.l:181 { yy.Context.lval.s = string(yytext) return Token(_STRING_IDENTIFIER_); @@ -1226,7 +1226,7 @@ case 45: } -//line lexer.l:187 +//line parser/lexer.l:187 { yy.Context.lval.s = string(yytext) return Token(_STRING_COUNT_); @@ -1241,7 +1241,7 @@ case 46: } -//line lexer.l:193 +//line parser/lexer.l:193 { yy.Context.lval.s = string(yytext) return Token(_STRING_OFFSET_); @@ -1256,7 +1256,7 @@ case 47: } -//line lexer.l:199 +//line parser/lexer.l:199 { yy.Context.lval.s = string(yytext) return Token(_STRING_LENGTH_); @@ -1271,7 +1271,7 @@ case 48: } -//line lexer.l:205 +//line parser/lexer.l:205 { yy.Context.lval.s = string(yytext) return Token(_INTEGER_FUNCTION_); @@ -1286,7 +1286,7 @@ case 49: } -//line lexer.l:211 +//line parser/lexer.l:211 { yy.Context.lval.s = string(yytext) return Token(_IDENTIFIER_); @@ -1301,7 +1301,7 @@ case 50: } -//line lexer.l:217 +//line parser/lexer.l:217 { var err error s := strings.TrimRight(YYtext, "MKB") @@ -1341,7 +1341,7 @@ case 51: } -//line lexer.l:247 +//line parser/lexer.l:247 { return Token(_DOUBLE_); } @@ -1355,7 +1355,7 @@ case 52: } -//line lexer.l:251 +//line parser/lexer.l:251 { var err error yy.Context.lval.i64, err = strconv.ParseInt(YYtext, 0, 64) @@ -1377,7 +1377,7 @@ case 53: } -//line lexer.l:263 +//line parser/lexer.l:263 { var err error s := strings.TrimLeft(YYtext, "0o") @@ -1399,7 +1399,7 @@ case 54: } -//line lexer.l:276 +//line parser/lexer.l:276 { /* saw closing quote - all done */ // NOTE: text will end with `"` char @@ -1420,7 +1420,7 @@ case 55: } -//line lexer.l:288 +//line parser/lexer.l:288 { } case 56: @@ -1433,7 +1433,7 @@ case 56: } -//line lexer.l:292 +//line parser/lexer.l:292 { } case 57: @@ -1446,7 +1446,7 @@ case 57: } -//line lexer.l:296 +//line parser/lexer.l:296 { } case 58: @@ -1459,7 +1459,7 @@ case 58: } -//line lexer.l:300 +//line parser/lexer.l:300 { } case 59: @@ -1472,7 +1472,7 @@ case 59: } -//line lexer.l:304 +//line parser/lexer.l:304 { } case 60: @@ -1485,7 +1485,7 @@ case 60: } -//line lexer.l:308 +//line parser/lexer.l:308 { } case 61: /* rule 61 can match eol */ @@ -1498,7 +1498,7 @@ case 61: } -//line lexer.l:311 +//line parser/lexer.l:311 { return Error( gyperror.UnterminatedStringError, @@ -1515,7 +1515,7 @@ case 62: } -//line lexer.l:318 +//line parser/lexer.l:318 { return Error( gyperror.IllegalEscapeSequenceError, @@ -1531,7 +1531,7 @@ case 63: } -//line lexer.l:325 +//line parser/lexer.l:325 { collectText = false @@ -1573,7 +1573,7 @@ case 64: } -//line lexer.l:358 +//line parser/lexer.l:358 { } case 65: @@ -1586,7 +1586,7 @@ case 65: } -//line lexer.l:362 +//line parser/lexer.l:362 { } case 66: @@ -1599,7 +1599,7 @@ case 66: } -//line lexer.l:366 +//line parser/lexer.l:366 { } case 67: /* rule 67 can match eol */ @@ -1612,7 +1612,7 @@ case 67: } -//line lexer.l:369 +//line parser/lexer.l:369 { return Error( gyperror.UnterminatedRegexError, @@ -1628,7 +1628,7 @@ case 68: } -//line lexer.l:376 +//line parser/lexer.l:376 { collectText = true text = []byte{} @@ -1644,7 +1644,7 @@ case 69: } -//line lexer.l:383 +//line parser/lexer.l:383 { collectText = true text = []byte{} @@ -1661,7 +1661,7 @@ case 70: } -//line lexer.l:390 +//line parser/lexer.l:390 { // Match hex-digits with whitespace or comments. The latter are stripped // out by hex_lexer.l @@ -1690,7 +1690,7 @@ case 71: } -//line lexer.l:409 +//line parser/lexer.l:409 /* skip whitespace */ case 72: @@ -1702,7 +1702,7 @@ case 72: } -//line lexer.l:411 +//line parser/lexer.l:411 { r := int(yytext[0]) @@ -1725,9 +1725,9 @@ case 73: } -//line lexer.l:424 +//line parser/lexer.l:424 yyout.Write(yytext) -//line lexer.go:1731 +//line parser/lexer.go:1731 // SKEL ---------------------------------------------------------------- case yyEndOfBuffer: @@ -2188,7 +2188,7 @@ func YYmain(filenames ...string) (interface{}, error) { } // END OF SKELL -------------------------------------------------------- -//line lexer.l:424 +//line parser/lexer.l:424 diff --git a/lexer.l b/parser/lexer.l similarity index 99% rename from lexer.l rename to parser/lexer.l index 667c364..7ff0d93 100644 --- a/lexer.l +++ b/parser/lexer.l @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* Lexical analyzer for YARA */ %top{ -package gyp +package parser import ( "fmt" diff --git a/parser.go b/parser/parser.go similarity index 85% rename from parser.go rename to parser/parser.go index 64e4b3b..740320d 100644 --- a/parser.go +++ b/parser/parser.go @@ -1,14 +1,17 @@ -// Code generated by goyacc -p yr -o parser.go grammar.y. DO NOT EDIT. +// Code generated by goyacc -p yr -o parser/parser.go parser/grammar.y. DO NOT EDIT. -//line grammar.y:31 -package gyp +//line parser/grammar.y:31 +package parser import __yyfmt__ "fmt" -//line grammar.y:31 +//line parser/grammar.y:31 import ( + "fmt" "github.com/VirusTotal/gyp/ast" gyperror "github.com/VirusTotal/gyp/error" + "io" + "io/ioutil" "strings" ) @@ -31,7 +34,91 @@ type stringModifiers struct { XorMax int32 } -//line grammar.y:161 +// Lexer is an adapter that fits the flexgo lexer ("Scanner") into goyacc +type lexer struct { + scanner Scanner + err gyperror.Error + ruleSet *ast.RuleSet +} + +// Lex provides the interface expected by the goyacc parser. +// It sets the context's lval pointer (defined in the lexer file) +// to the one passed as an argument so that the parser actions +// can make use of it. +func (l *lexer) Lex(lval *yrSymType) int { + l.scanner.Context.lval = lval + r := l.scanner.Lex() + if r.Error.Code != 0 { + r.Error.Line = l.scanner.Lineno + panic(r.Error) + } + return r.Token +} + +// Error satisfies the interface expected of the goyacc parser. +func (l *lexer) Error(msg string) { + l.err = gyperror.Error{ + Code: gyperror.LexicalError, + Line: l.scanner.Lineno, + Message: msg, + } +} + +// setError sets the lexer error. The error message can be built by passing +// a format string and arguments as fmt.Sprintf. This function returns 1 as +// it's intended to be used by Parse as: +// return lexer.setError(...) +// By returning 1 from Parse the parsing is aborted. +func (l *lexer) setError(code gyperror.Code, format string, a ...interface{}) int { + l.err = gyperror.Error{ + Code: code, + Line: l.scanner.Lineno, + Message: fmt.Sprintf(format, a...), + } + return 1 +} + +// Helper function that casts a yrLexer interface to a lexer struct. +func asLexer(l yrLexer) *lexer { + return l.(*lexer) +} + +func Parse(input io.Reader) (rs *ast.RuleSet, err error) { + defer func() { + if r := recover(); r != nil { + if yaraError, ok := r.(gyperror.Error); ok { + err = yaraError + } else { + err = gyperror.Error{ + Code: gyperror.UnknownError, + Message: fmt.Sprintf("%v", r), + } + } + } + }() + + lexer := &lexer{ + scanner: *NewScanner(), + ruleSet: &ast.RuleSet{ + Imports: make([]string, 0), + Rules: make([]*ast.Rule, 0), + }, + } + lexer.scanner.In = input + lexer.scanner.Out = ioutil.Discard + + if result := yrParse(lexer); result != 0 { + err = lexer.err + } + + return lexer.ruleSet, err +} + +func init() { + yrErrorVerbose = true +} + +//line parser/grammar.y:251 type yrSymType struct { yys int i64 int64 @@ -192,7 +279,7 @@ const yrEofCode = 1 const yrErrCode = 2 const yrInitialStackSize = 16 -//line grammar.y:996 +//line parser/grammar.y:1086 // This function takes an operator and two operands and returns a Expression // representing the operation. If the left operand is an operation of the @@ -768,47 +855,47 @@ yrdefault: case 2: yrDollar = yrS[yrpt-2 : yrpt+1] -//line grammar.y:191 +//line parser/grammar.y:281 { ruleSet := asLexer(yrlex).ruleSet ruleSet.Rules = append(ruleSet.Rules, yrDollar[2].rule) } case 3: yrDollar = yrS[yrpt-2 : yrpt+1] -//line grammar.y:196 +//line parser/grammar.y:286 { ruleSet := asLexer(yrlex).ruleSet ruleSet.Imports = append(ruleSet.Imports, yrDollar[2].s) } case 4: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:201 +//line parser/grammar.y:291 { ruleSet := asLexer(yrlex).ruleSet ruleSet.Includes = append(ruleSet.Includes, yrDollar[3].s) } case 5: yrDollar = yrS[yrpt-2 : yrpt+1] -//line grammar.y:206 +//line parser/grammar.y:296 { } case 6: yrDollar = yrS[yrpt-2 : yrpt+1] -//line grammar.y:214 +//line parser/grammar.y:304 { yrVAL.s = yrDollar[2].s } case 7: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:222 +//line parser/grammar.y:312 { lexer := asLexer(yrlex) // Forbid duplicate rules for _, r := range lexer.ruleSet.Rules { if yrDollar[3].s == r.Identifier { - return lexer.SetError( + return lexer.setError( gyperror.DuplicateRuleError, `duplicate rule "%s"`, yrDollar[3].s) } } @@ -821,7 +908,7 @@ yrdefault: } case 8: yrDollar = yrS[yrpt-8 : yrpt+1] -//line grammar.y:240 +//line parser/grammar.y:330 { yrDollar[4].rule.Tags = yrDollar[5].ss yrDollar[4].rule.Meta = yrDollar[7].metas @@ -829,92 +916,92 @@ yrdefault: } case 9: yrDollar = yrS[yrpt-11 : yrpt+1] -//line grammar.y:246 +//line parser/grammar.y:336 { yrDollar[4].rule.Condition = yrDollar[10].expr yrVAL.rule = yrDollar[4].rule } case 10: yrDollar = yrS[yrpt-0 : yrpt+1] -//line grammar.y:255 +//line parser/grammar.y:345 { yrVAL.metas = []*ast.Meta{} } case 11: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:259 +//line parser/grammar.y:349 { yrVAL.metas = yrDollar[3].metas } case 12: yrDollar = yrS[yrpt-0 : yrpt+1] -//line grammar.y:267 +//line parser/grammar.y:357 { yrVAL.yss = []ast.String{} } case 13: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:271 +//line parser/grammar.y:361 { yrVAL.yss = yrDollar[3].yss } case 14: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:279 +//line parser/grammar.y:369 { yrVAL.expr = yrDollar[3].expr } case 15: yrDollar = yrS[yrpt-0 : yrpt+1] -//line grammar.y:287 +//line parser/grammar.y:377 { yrVAL.mod = 0 } case 16: yrDollar = yrS[yrpt-2 : yrpt+1] -//line grammar.y:291 +//line parser/grammar.y:381 { yrVAL.mod = yrDollar[1].mod | yrDollar[2].mod } case 17: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:299 +//line parser/grammar.y:389 { yrVAL.mod = ModPrivate } case 18: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:303 +//line parser/grammar.y:393 { yrVAL.mod = ModGlobal } case 19: yrDollar = yrS[yrpt-0 : yrpt+1] -//line grammar.y:311 +//line parser/grammar.y:401 { yrVAL.ss = []string{} } case 20: yrDollar = yrS[yrpt-2 : yrpt+1] -//line grammar.y:315 +//line parser/grammar.y:405 { yrVAL.ss = yrDollar[2].ss } case 21: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:323 +//line parser/grammar.y:413 { yrVAL.ss = []string{yrDollar[1].s} } case 22: yrDollar = yrS[yrpt-2 : yrpt+1] -//line grammar.y:327 +//line parser/grammar.y:417 { lexer := asLexer(yrlex) for _, tag := range yrDollar[1].ss { if tag == yrDollar[2].s { - return lexer.SetError( + return lexer.setError( gyperror.DuplicateTagError, `duplicate tag "%s"`, yrDollar[2].s) } } @@ -923,19 +1010,19 @@ yrdefault: } case 23: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:344 +//line parser/grammar.y:434 { yrVAL.metas = []*ast.Meta{yrDollar[1].meta} } case 24: yrDollar = yrS[yrpt-2 : yrpt+1] -//line grammar.y:348 +//line parser/grammar.y:438 { yrVAL.metas = append(yrDollar[1].metas, yrDollar[2].meta) } case 25: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:356 +//line parser/grammar.y:446 { yrVAL.meta = &ast.Meta{ Key: yrDollar[1].s, @@ -944,7 +1031,7 @@ yrdefault: } case 26: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:363 +//line parser/grammar.y:453 { yrVAL.meta = &ast.Meta{ Key: yrDollar[1].s, @@ -953,7 +1040,7 @@ yrdefault: } case 27: yrDollar = yrS[yrpt-4 : yrpt+1] -//line grammar.y:370 +//line parser/grammar.y:460 { yrVAL.meta = &ast.Meta{ Key: yrDollar[1].s, @@ -962,7 +1049,7 @@ yrdefault: } case 28: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:377 +//line parser/grammar.y:467 { yrVAL.meta = &ast.Meta{ Key: yrDollar[1].s, @@ -971,7 +1058,7 @@ yrdefault: } case 29: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:384 +//line parser/grammar.y:474 { yrVAL.meta = &ast.Meta{ Key: yrDollar[1].s, @@ -980,19 +1067,19 @@ yrdefault: } case 30: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:395 +//line parser/grammar.y:485 { yrVAL.yss = []ast.String{yrDollar[1].ys} } case 31: yrDollar = yrS[yrpt-2 : yrpt+1] -//line grammar.y:399 +//line parser/grammar.y:489 { yrVAL.yss = append(yrDollar[1].yss, yrDollar[2].ys) } case 32: yrDollar = yrS[yrpt-4 : yrpt+1] -//line grammar.y:407 +//line parser/grammar.y:497 { yrVAL.ys = &ast.TextString{ Identifier: strings.TrimPrefix(yrDollar[1].s, "$"), @@ -1009,7 +1096,7 @@ yrdefault: } case 33: yrDollar = yrS[yrpt-4 : yrpt+1] -//line grammar.y:422 +//line parser/grammar.y:512 { yrVAL.ys = &ast.RegexpString{ Identifier: strings.TrimPrefix(yrDollar[1].s, "$"), @@ -1023,7 +1110,7 @@ yrdefault: } case 34: yrDollar = yrS[yrpt-4 : yrpt+1] -//line grammar.y:434 +//line parser/grammar.y:524 { yrVAL.ys = &ast.HexString{ Identifier: strings.TrimPrefix(yrDollar[1].s, "$"), @@ -1033,16 +1120,16 @@ yrdefault: } case 35: yrDollar = yrS[yrpt-0 : yrpt+1] -//line grammar.y:446 +//line parser/grammar.y:536 { yrVAL.smod = stringModifiers{} } case 36: yrDollar = yrS[yrpt-2 : yrpt+1] -//line grammar.y:450 +//line parser/grammar.y:540 { if yrDollar[1].smod.modifiers&yrDollar[2].smod.modifiers != 0 { - return asLexer(yrlex).SetError( + return asLexer(yrlex).setError( gyperror.DuplicateModifierError, `duplicate modifier`) } @@ -1057,37 +1144,37 @@ yrdefault: } case 37: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:469 +//line parser/grammar.y:559 { yrVAL.smod = stringModifiers{modifiers: ModWide} } case 38: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:470 +//line parser/grammar.y:560 { yrVAL.smod = stringModifiers{modifiers: ModASCII} } case 39: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:471 +//line parser/grammar.y:561 { yrVAL.smod = stringModifiers{modifiers: ModNocase} } case 40: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:472 +//line parser/grammar.y:562 { yrVAL.smod = stringModifiers{modifiers: ModFullword} } case 41: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:473 +//line parser/grammar.y:563 { yrVAL.smod = stringModifiers{modifiers: ModPrivate} } case 42: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:475 +//line parser/grammar.y:565 { yrVAL.smod = stringModifiers{ modifiers: ModXor, @@ -1097,7 +1184,7 @@ yrdefault: } case 43: yrDollar = yrS[yrpt-4 : yrpt+1] -//line grammar.y:483 +//line parser/grammar.y:573 { yrVAL.smod = stringModifiers{ modifiers: ModXor, @@ -1107,24 +1194,24 @@ yrdefault: } case 44: yrDollar = yrS[yrpt-6 : yrpt+1] -//line grammar.y:491 +//line parser/grammar.y:581 { lexer := asLexer(yrlex) if yrDollar[3].i64 < 0 { - return lexer.SetError( + return lexer.setError( gyperror.InvalidStringModifierError, "lower bound for xor range exceeded (min: 0)") } if yrDollar[5].i64 > 255 { - return lexer.SetError( + return lexer.setError( gyperror.InvalidStringModifierError, "upper bound for xor range exceeded (max: 255)") } if yrDollar[3].i64 > yrDollar[5].i64 { - return lexer.SetError( + return lexer.setError( gyperror.InvalidStringModifierError, "xor lower bound exceeds upper bound") } @@ -1137,73 +1224,73 @@ yrdefault: } case 45: yrDollar = yrS[yrpt-0 : yrpt+1] -//line grammar.y:523 +//line parser/grammar.y:613 { yrVAL.mod = 0 } case 46: yrDollar = yrS[yrpt-2 : yrpt+1] -//line grammar.y:527 +//line parser/grammar.y:617 { yrVAL.mod = yrDollar[1].mod | yrDollar[2].mod } case 47: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:534 +//line parser/grammar.y:624 { yrVAL.mod = ModWide } case 48: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:535 +//line parser/grammar.y:625 { yrVAL.mod = ModASCII } case 49: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:536 +//line parser/grammar.y:626 { yrVAL.mod = ModNocase } case 50: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:537 +//line parser/grammar.y:627 { yrVAL.mod = ModFullword } case 51: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:538 +//line parser/grammar.y:628 { yrVAL.mod = ModPrivate } case 52: yrDollar = yrS[yrpt-0 : yrpt+1] -//line grammar.y:544 +//line parser/grammar.y:634 { yrVAL.mod = 0 } case 53: yrDollar = yrS[yrpt-2 : yrpt+1] -//line grammar.y:548 +//line parser/grammar.y:638 { yrVAL.mod = yrDollar[1].mod | yrDollar[2].mod } case 54: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:555 +//line parser/grammar.y:645 { yrVAL.mod = ModPrivate } case 55: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:561 +//line parser/grammar.y:651 { yrVAL.expr = &ast.Identifier{Identifier: yrDollar[1].s} } case 56: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:565 +//line parser/grammar.y:655 { yrVAL.expr = &ast.MemberAccess{ Container: yrDollar[1].expr, @@ -1212,7 +1299,7 @@ yrdefault: } case 57: yrDollar = yrS[yrpt-4 : yrpt+1] -//line grammar.y:572 +//line parser/grammar.y:662 { yrVAL.expr = &ast.Subscripting{ Array: yrDollar[1].expr, @@ -1221,7 +1308,7 @@ yrdefault: } case 58: yrDollar = yrS[yrpt-4 : yrpt+1] -//line grammar.y:579 +//line parser/grammar.y:669 { yrVAL.expr = &ast.FunctionCall{ Callable: yrDollar[1].expr, @@ -1230,55 +1317,55 @@ yrdefault: } case 59: yrDollar = yrS[yrpt-0 : yrpt+1] -//line grammar.y:590 +//line parser/grammar.y:680 { yrVAL.exprs = []ast.Expression{} } case 60: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:594 +//line parser/grammar.y:684 { yrVAL.exprs = yrDollar[1].exprs } case 61: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:601 +//line parser/grammar.y:691 { yrVAL.exprs = []ast.Expression{yrDollar[1].expr} } case 62: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:605 +//line parser/grammar.y:695 { yrVAL.exprs = append(yrDollar[1].exprs, yrDollar[3].expr) } case 63: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:613 +//line parser/grammar.y:703 { yrVAL.reg = yrDollar[1].reg } case 64: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:621 +//line parser/grammar.y:711 { yrVAL.expr = yrDollar[1].expr } case 65: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:629 +//line parser/grammar.y:719 { yrVAL.expr = ast.KeywordTrue } case 66: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:633 +//line parser/grammar.y:723 { yrVAL.expr = ast.KeywordFalse } case 67: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:637 +//line parser/grammar.y:727 { yrVAL.expr = &ast.Operation{ Operator: ast.OpMatches, @@ -1287,7 +1374,7 @@ yrdefault: } case 68: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:644 +//line parser/grammar.y:734 { yrVAL.expr = &ast.Operation{ Operator: ast.OpContains, @@ -1296,7 +1383,7 @@ yrdefault: } case 69: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:651 +//line parser/grammar.y:741 { yrVAL.expr = &ast.StringIdentifier{ Identifier: strings.TrimPrefix(yrDollar[1].s, "$"), @@ -1304,7 +1391,7 @@ yrdefault: } case 70: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:657 +//line parser/grammar.y:747 { yrVAL.expr = &ast.StringIdentifier{ Identifier: strings.TrimPrefix(yrDollar[1].s, "$"), @@ -1313,7 +1400,7 @@ yrdefault: } case 71: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:664 +//line parser/grammar.y:754 { yrVAL.expr = &ast.StringIdentifier{ Identifier: strings.TrimPrefix(yrDollar[1].s, "$"), @@ -1322,12 +1409,12 @@ yrdefault: } case 72: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:670 +//line parser/grammar.y:760 { } case 73: yrDollar = yrS[yrpt-9 : yrpt+1] -//line grammar.y:672 +//line parser/grammar.y:762 { yrVAL.expr = &ast.ForIn{ Quantifier: yrDollar[2].quantifier, @@ -1338,7 +1425,7 @@ yrdefault: } case 74: yrDollar = yrS[yrpt-8 : yrpt+1] -//line grammar.y:681 +//line parser/grammar.y:771 { yrVAL.expr = &ast.ForOf{ Quantifier: yrDollar[2].quantifier, @@ -1348,7 +1435,7 @@ yrdefault: } case 75: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:689 +//line parser/grammar.y:779 { yrVAL.expr = &ast.Of{ Quantifier: yrDollar[1].quantifier, @@ -1357,25 +1444,25 @@ yrdefault: } case 76: yrDollar = yrS[yrpt-2 : yrpt+1] -//line grammar.y:696 +//line parser/grammar.y:786 { yrVAL.expr = &ast.Not{yrDollar[2].expr} } case 77: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:700 +//line parser/grammar.y:790 { yrVAL.expr = operation(ast.OpAnd, yrDollar[1].expr, yrDollar[3].expr) } case 78: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:704 +//line parser/grammar.y:794 { yrVAL.expr = operation(ast.OpOr, yrDollar[1].expr, yrDollar[3].expr) } case 79: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:708 +//line parser/grammar.y:798 { yrVAL.expr = &ast.Operation{ Operator: ast.OpLessThan, @@ -1384,7 +1471,7 @@ yrdefault: } case 80: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:715 +//line parser/grammar.y:805 { yrVAL.expr = &ast.Operation{ Operator: ast.OpGreaterThan, @@ -1393,7 +1480,7 @@ yrdefault: } case 81: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:722 +//line parser/grammar.y:812 { yrVAL.expr = &ast.Operation{ Operator: ast.OpLessOrEqual, @@ -1402,7 +1489,7 @@ yrdefault: } case 82: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:729 +//line parser/grammar.y:819 { yrVAL.expr = &ast.Operation{ Operator: ast.OpGreaterOrEqual, @@ -1411,7 +1498,7 @@ yrdefault: } case 83: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:736 +//line parser/grammar.y:826 { yrVAL.expr = &ast.Operation{ Operator: ast.OpEqual, @@ -1420,7 +1507,7 @@ yrdefault: } case 84: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:743 +//line parser/grammar.y:833 { yrVAL.expr = &ast.Operation{ Operator: ast.OpNotEqual, @@ -1429,31 +1516,31 @@ yrdefault: } case 85: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:750 +//line parser/grammar.y:840 { yrVAL.expr = yrDollar[1].expr } case 86: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:754 +//line parser/grammar.y:844 { yrVAL.expr = &ast.Group{yrDollar[2].expr} } case 87: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:762 +//line parser/grammar.y:852 { yrVAL.node = &ast.Enum{Values: yrDollar[2].exprs} } case 88: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:766 +//line parser/grammar.y:856 { yrVAL.node = yrDollar[1].rng } case 89: yrDollar = yrS[yrpt-5 : yrpt+1] -//line grammar.y:774 +//line parser/grammar.y:864 { yrVAL.rng = &ast.Range{ Start: yrDollar[2].expr, @@ -1462,43 +1549,43 @@ yrdefault: } case 90: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:785 +//line parser/grammar.y:875 { yrVAL.exprs = []ast.Expression{yrDollar[1].expr} } case 91: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:789 +//line parser/grammar.y:879 { yrVAL.exprs = append(yrDollar[1].exprs, yrDollar[3].expr) } case 92: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:797 +//line parser/grammar.y:887 { yrVAL.node = &ast.Enum{Values: yrDollar[2].exprs} } case 93: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:801 +//line parser/grammar.y:891 { yrVAL.node = ast.KeywordThem } case 94: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:809 +//line parser/grammar.y:899 { yrVAL.exprs = []ast.Expression{yrDollar[1].si} } case 95: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:813 +//line parser/grammar.y:903 { yrVAL.exprs = append(yrDollar[1].exprs, yrDollar[3].si) } case 96: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:821 +//line parser/grammar.y:911 { yrVAL.si = &ast.StringIdentifier{ Identifier: strings.TrimPrefix(yrDollar[1].s, "$"), @@ -1506,7 +1593,7 @@ yrdefault: } case 97: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:827 +//line parser/grammar.y:917 { yrVAL.si = &ast.StringIdentifier{ Identifier: strings.TrimPrefix(yrDollar[1].s, "$"), @@ -1514,67 +1601,67 @@ yrdefault: } case 98: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:837 +//line parser/grammar.y:927 { yrVAL.quantifier = &ast.Quantifier{yrDollar[1].expr} } case 99: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:841 +//line parser/grammar.y:931 { yrVAL.quantifier = &ast.Quantifier{ast.KeywordAll} } case 100: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:845 +//line parser/grammar.y:935 { yrVAL.quantifier = &ast.Quantifier{ast.KeywordAny} } case 101: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:853 +//line parser/grammar.y:943 { yrVAL.ss = []string{yrDollar[1].s} } case 102: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:857 +//line parser/grammar.y:947 { yrVAL.ss = append(yrDollar[1].ss, yrDollar[3].s) } case 103: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:864 +//line parser/grammar.y:954 { yrVAL.node = yrDollar[1].expr } case 104: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:868 +//line parser/grammar.y:958 { yrVAL.node = yrDollar[1].node } case 105: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:876 +//line parser/grammar.y:966 { yrVAL.expr = &ast.Group{yrDollar[2].expr} } case 106: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:880 +//line parser/grammar.y:970 { yrVAL.expr = ast.KeywordFilesize } case 107: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:884 +//line parser/grammar.y:974 { yrVAL.expr = ast.KeywordEntrypoint } case 108: yrDollar = yrS[yrpt-4 : yrpt+1] -//line grammar.y:888 +//line parser/grammar.y:978 { yrVAL.expr = &ast.FunctionCall{ Callable: &ast.Identifier{Identifier: yrDollar[1].s}, @@ -1583,25 +1670,25 @@ yrdefault: } case 109: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:895 +//line parser/grammar.y:985 { yrVAL.expr = &ast.LiteralInteger{yrDollar[1].i64} } case 110: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:899 +//line parser/grammar.y:989 { yrVAL.expr = &ast.LiteralFloat{yrDollar[1].f64} } case 111: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:903 +//line parser/grammar.y:993 { yrVAL.expr = &ast.LiteralString{yrDollar[1].s} } case 112: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:907 +//line parser/grammar.y:997 { yrVAL.expr = &ast.StringCount{ Identifier: strings.TrimPrefix(yrDollar[1].s, "#"), @@ -1609,7 +1696,7 @@ yrdefault: } case 113: yrDollar = yrS[yrpt-4 : yrpt+1] -//line grammar.y:913 +//line parser/grammar.y:1003 { yrVAL.expr = &ast.StringOffset{ Identifier: strings.TrimPrefix(yrDollar[1].s, "@"), @@ -1618,7 +1705,7 @@ yrdefault: } case 114: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:920 +//line parser/grammar.y:1010 { yrVAL.expr = &ast.StringOffset{ Identifier: strings.TrimPrefix(yrDollar[1].s, "@"), @@ -1626,7 +1713,7 @@ yrdefault: } case 115: yrDollar = yrS[yrpt-4 : yrpt+1] -//line grammar.y:926 +//line parser/grammar.y:1016 { yrVAL.expr = &ast.StringLength{ Identifier: strings.TrimPrefix(yrDollar[1].s, "!"), @@ -1635,7 +1722,7 @@ yrdefault: } case 116: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:933 +//line parser/grammar.y:1023 { yrVAL.expr = &ast.StringLength{ Identifier: strings.TrimPrefix(yrDollar[1].s, "!"), @@ -1643,85 +1730,85 @@ yrdefault: } case 117: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:939 +//line parser/grammar.y:1029 { yrVAL.expr = yrDollar[1].expr } case 118: yrDollar = yrS[yrpt-2 : yrpt+1] -//line grammar.y:943 +//line parser/grammar.y:1033 { yrVAL.expr = &ast.Minus{yrDollar[2].expr} } case 119: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:947 +//line parser/grammar.y:1037 { yrVAL.expr = operation(ast.OpAdd, yrDollar[1].expr, yrDollar[3].expr) } case 120: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:951 +//line parser/grammar.y:1041 { yrVAL.expr = operation(ast.OpSub, yrDollar[1].expr, yrDollar[3].expr) } case 121: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:955 +//line parser/grammar.y:1045 { yrVAL.expr = operation(ast.OpMul, yrDollar[1].expr, yrDollar[3].expr) } case 122: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:959 +//line parser/grammar.y:1049 { yrVAL.expr = operation(ast.OpDiv, yrDollar[1].expr, yrDollar[3].expr) } case 123: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:963 +//line parser/grammar.y:1053 { yrVAL.expr = operation(ast.OpMod, yrDollar[1].expr, yrDollar[3].expr) } case 124: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:967 +//line parser/grammar.y:1057 { yrVAL.expr = operation(ast.OpBitXor, yrDollar[1].expr, yrDollar[3].expr) } case 125: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:971 +//line parser/grammar.y:1061 { yrVAL.expr = operation(ast.OpBitAnd, yrDollar[1].expr, yrDollar[3].expr) } case 126: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:975 +//line parser/grammar.y:1065 { yrVAL.expr = operation(ast.OpBitOr, yrDollar[1].expr, yrDollar[3].expr) } case 127: yrDollar = yrS[yrpt-2 : yrpt+1] -//line grammar.y:979 +//line parser/grammar.y:1069 { yrVAL.expr = &ast.BitwiseNot{yrDollar[2].expr} } case 128: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:983 +//line parser/grammar.y:1073 { yrVAL.expr = operation(ast.OpShiftLeft, yrDollar[1].expr, yrDollar[3].expr) } case 129: yrDollar = yrS[yrpt-3 : yrpt+1] -//line grammar.y:987 +//line parser/grammar.y:1077 { yrVAL.expr = operation(ast.OpShiftRight, yrDollar[1].expr, yrDollar[3].expr) } case 130: yrDollar = yrS[yrpt-1 : yrpt+1] -//line grammar.y:991 +//line parser/grammar.y:1081 { yrVAL.expr = yrDollar[1].reg }