lib/protobuf/compiler/proto.y in ruby_protobuf-0.3.2 vs lib/protobuf/compiler/proto.y in ruby_protobuf-0.3.3
- old
+ new
@@ -1,7 +1,6 @@
class Protobuf::ProtoParser
- #options no_result_var
rule
proto : proto_item
{ result = Protobuf::Node::ProtoNode.new val }
| proto proto_item
{ result.children << val[1] }
@@ -103,15 +102,17 @@
{ }
group : label 'group' CAMEL_IDENT '=' integer_literal message_body
{ result = Protobuf::Node::GroupNode.new val[0], val[2], val[4], val[5] }
- field : label type IDENT '=' integer_literal ';'
+ field : label type field_name '=' integer_literal ';'
{ result = Protobuf::Node::FieldNode.new val[0], val[1], val[2], val[4] }
- | label type IDENT '=' integer_literal '[' field_option_list ']' ';'
+ | label type field_name '=' integer_literal '[' field_option_list ']' ';'
{ result = Protobuf::Node::FieldNode.new val[0], val[1], val[2], val[4], val[6] }
+ field_name : IDENT | "required" | "optional" | "repeated" | "import" | "package" | "option" | "message" | "extend" | "enum" | "service" | "rpc" | "returns" | "group" | "default" | "extensions" | "to" | "max" | "double" | "float" | "int32" | "int64" | "uint32" | "uint64" | "sint32" | "sint64" | "fixed32" | "fixed64" | "sfixed32" | "sfixed64" | "bool" | "string" | "bytes"
+
field_option_list : field_option
{ result = val }
| field_option_list ',' field_option
{ result << val[2] }
@@ -158,44 +159,63 @@
| OCT_INTEGER
end
---- inner
+ require 'strscan'
+
def parse(f)
- @q = []
- f.each do |line|
- until line.empty? do
- case line
- when /\A\s+/, /\A\/\/.*/
- ;
- when /\A(required|optional|repeated|import|package|option|message|extend|enum|service|rpc|returns|group|default|extensions|to|max|double|float|int32|int64|uint32|uint64|sint32|sint64|fixed32|fixed64|sfixed32|sfixed64|bool|string|bytes)\b/
- @q.push [$&, $&.to_sym]
- when /\A[1-9]\d*(?!\.)/, /\A0(?![.xX0-9])/
- @q.push [:DEC_INTEGER, $&.to_i]
- when /\A0[xX]([A-Fa-f0-9])+/
- @q.push [:HEX_INTEGER, $&.to_i(0)]
- when /\A0[0-7]+/
- @q.push [:OCT_INTEGER, $&.to_i(0)]
- when /\A\d+(\.\d+)?([Ee][\+-]?\d+)?/
- @q.push [:FLOAT_LITERAL, $&.to_f]
- when /\A(true|false)/
- @q.push [:BOOLEAN_LITERAL, $& == 'true']
- when /\A"(?:[^"\\]+|\\.)*"/, /\A'(?:[^'\\]+|\\.)*'/
- @q.push [:STRING_LITERAL, eval($&)]
- when /\A[a-zA-Z_][\w_]*/
- @q.push [:IDENT, $&.to_sym]
- when /\A[A-Z][\w_]*/
- @q.push [:CAMEL_IDENT, $&.to_sym]
- when /\A./
- @q.push [$&, $&]
- else
- raise ArgumentError.new(line)
- end
- line = $'
+ @scanner = StringScanner.new(f.read)
+ yyparse(self, :scan)
+ end
+
+ def scan_debug
+ scan do |token, value|
+ p [token, value]
+ yield [token, value]
+ end
+ end
+
+ def scan
+ until @scanner.eos?
+ case
+ when match(/\s+/, /\/\/.*/)
+ # skip
+ when match(/\/\*/)
+ # C-like comment
+ raise 'EOF inside block comment' until @scanner.scan_until(/\*\//)
+ when match(/(?:required|optional|repeated|import|package|option|message|extend|enum|service|rpc|returns|group|default|extensions|to|max|double|float|int32|int64|uint32|uint64|sint32|sint64|fixed32|fixed64|sfixed32|sfixed64|bool|string|bytes)\b/)
+ yield [@token, @token.to_sym]
+ when match(/[+-]?\d*\.\d+([Ee][\+-]?\d+)?/)
+ yield [:FLOAT_LITERAL, @token.to_f]
+ when match(/[+-]?[1-9]\d*(?!\.)/, /0(?![.xX0-9])/)
+ yield [:DEC_INTEGER, @token.to_i]
+ when match(/0[xX]([A-Fa-f0-9])+/)
+ yield [:HEX_INTEGER, @token.to_i(0)]
+ when match(/0[0-7]+/)
+ yield [:OCT_INTEGER, @token.to_i(0)]
+ when match(/(true|false)\b/)
+ yield [:BOOLEAN_LITERAL, @token == 'true']
+ when match(/"(?:[^"\\]+|\\.)*"/, /'(?:[^'\\]+|\\.)*'/)
+ yield [:STRING_LITERAL, eval(@token)]
+ when match(/[a-zA-Z_][\w_]*/)
+ yield [:IDENT, @token.to_sym]
+ when match(/[A-Z][\w_]*/)
+ yield [:CAMEL_IDENT, @token.to_sym]
+ when match(/./)
+ yield [@token, @token]
+ else
+ raise "parse error around #{@scanner.string[@scanner.pos, 32].inspect}"
end
end
- do_parse
+ yield [false, nil]
end
- def next_token
- @q.shift
+ def match(*regular_expressions)
+ regular_expressions.each do |re|
+ if @scanner.scan(re)
+ @token = @scanner[0]
+ return true
+ end
+ end
+ false
end