├── Makefile
├── README.md
├── bootstrap.sh
├── dsl
├── ProtoLexer.g
└── ProtoParser.g
├── protos
├── bases.proto
├── main.proto
├── messages.proto
├── options.proto
└── services.proto
├── sampleparser
├── MANIFEST.MF
├── SampleExceptionHandler.java
├── SampleParser.java
├── SampleProtoLexer.java
└── SampleProtoParser.java
└── urls.html
/Makefile:
--------------------------------------------------------------------------------
1 | ifeq ($(uname),Darwin)
2 | FLAGS += -arch i386
3 | endif
4 |
5 | sampleparser.jar : dsl/ProtoParser.java dsl/ProtoLexer.java sampleparser/MANIFEST.MF sampleparser/*.java
6 | @echo "building sampleparser.jar"
7 | @javac -classpath lib/antlr-runtime-3.2.jar:lib/commons-cli-1.2.jar:lib/guava-13.0.1.jar:. dsl/*.java sampleparser/*.java
8 | @jar -cfm sampleparser.jar sampleparser/MANIFEST.MF dsl/*.class sampleparser/*.class
9 | @rm -f *.class
10 |
11 | dsl/ProtoParser.java : dsl/ProtoParser.g dsl/ProtoLexer.tokens
12 | @echo "building parser"
13 | @java -jar lib/antlr-3.2.jar -fo dsl/ dsl/ProtoParser.g
14 |
15 | dsl/ProtoParser.tokens : dsl/ProtoParser.g dsl/ProtoLexer.tokens
16 | @echo "building parser"
17 | @java -jar lib/antlr-3.2.jar -fo dsl/ dsl/ProtoParser.g
18 |
19 | dsl/ProtoLexer.java : dsl/ProtoLexer.g
20 | @echo "building lexer"
21 | @java -jar lib/antlr-3.2.jar -fo dsl/ dsl/ProtoLexer.g
22 |
23 | dsl/ProtoLexer.tokens : dsl/ProtoLexer.g
24 | @echo "building lexer"
25 | @java -jar lib/antlr-3.2.jar -fo dsl/ dsl/ProtoLexer.g
26 |
27 | clean :
28 | @rm -f dsl/*.java dsl/*.tokens dsl/*.class sampleparser/*.class sampleparser.jar
29 |
30 | cleanclean : clean
31 | @rm -rf lib
32 |
33 | testparsersimple : sampleparser.jar
34 | @java -jar sampleparser.jar protos/*.proto
35 |
36 | testparserverbose : sampleparser.jar
37 | @java -jar sampleparser.jar protos/*.proto -t
38 |
39 | testprotos :
40 | @if [ -d output ]; then true; else mkdir output; fi
41 | @protoc --proto_path=/usr/local/include:protos/:. --java_out=./output/ --cpp_out=./output/ --python_out=./output/ protos/*.proto
42 | @rm -rf ./output
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Protobuf Parser
2 | ===============
3 |
4 | Overview
5 | --------
6 |
7 | The goal of this project is to provide an open-sourced, easy-to-use Protocol Buffer parser for further usage. Protocol Buffer is ["Google's data interchange format"](http://code.google.com/p/protobuf/), which is generously open-sourced. It is widely used as the wire-format for RPC and structure data record. For extended reading on this topic, please refer to its [documentation](https://developers.google.com/protocol-buffers/docs/overview).
8 |
9 | The offical Protocol Buffer distribution generally includes 3 components:
10 | - **Language-specific Message Compiler** Protocol Buffer is described in a [DSL (Domain Specific Language)](https://developers.google.com/protocol-buffers/docs/proto). So compilers are provided to translate the DSL to native languages - C++, Java and Python are "officially" provided by Google and there are many "third-party" ones.
11 | - **Language-specific Message Runtime** The compiler only translates the DSL into native language, so the runtime is provided to handle actual works such like encoding, decoding etc. Again, C++, Java and Python are "officially supported".
12 | - **Language-specific Service Compiler** _This is an deprecated feature provided by Google._ In the above DSL, customer may define the RPC service using service
and rpc
keywords. However, since the service runtime is not provided, it may not be that helpful to use the generated service "stub" code in native language.
13 |
14 | This project provides a fully-compatible Protocol Buffer parser based on [Antlr 3](http://antlr.org/). It enables developers to:
15 | - generate the message definition in native language, say Javascript, for a given proto file, and
16 | - generate the service definition in native language.
17 |
18 | This project is inspired by [sirikata's ProtoJs project](https://github.com/sirikata/protojs) which uses Antlr as well, but fully rewrote.
19 |
20 | Install
21 | -------
22 |
23 | git clone git://github.com/yesme/protobuf-parser.git
24 | cd protobuf-parser
25 | ./bootstrap.sh
26 | make
27 |
28 | After that, a sample parser will be built.
29 |
30 | How does it work
31 | ----------------
32 |
33 | This project includes 3 components:
34 | - dsl
: Antlr grammar for Protocol Buffer
35 | - protos
: Sample Proto files basically covered most of the (normal and) corner cases defining a Protocol Buffer file
36 | - sampleparser
: A sample protobuf parser implementation
37 |
38 | Therefore make
will
39 | 1. build the DSL grammar into Java source code
40 | 2. build sampleparser
against the generated DSL source code
41 |
42 | For the one who wants to provide Protocol Buffer implementation, or provide Service implementation, please take a look at sampleparser/SampleParser.java
- it's a sample shows how to use it.
43 |
44 | In order to test the compatibility with protoc (Google's Protocol Buffer Compiler), run the following command:
45 |
46 | make testprotos
47 |
48 | In order to test the current parser, run the following commands. It will translate the input proto file into [AST (Abstract Syntax Tree)](http://en.wikipedia.org/wiki/Abstract_syntax_tree).
49 |
50 | make testparsersimple # simply test if the parser works
51 | make testparserverbose # run the parser and print out the AST
52 |
53 | For any question, please feel free to mail jacky.chao.wang@gmail.com for more information.
54 |
--------------------------------------------------------------------------------
/bootstrap.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | if [ -d lib ]; then
3 | true
4 | else
5 | mkdir lib
6 | fi
7 |
8 | if [ -e lib/antlr-3.2.jar ]; then
9 | true
10 | else
11 | echo "Downloading ANTLR 3.2 JAR from http://www.antlr.org/download.html"
12 | curl "http://www.antlr.org/download/antlr-3.2.jar" > lib/antlr-3.2.jar || \
13 | (echo "Failed to download ANTLR. Aborting.";rm -f lib/antlr-3.2.jar;exit 1)
14 | fi
15 |
16 | if [ -e lib/antlr-runtime-3.2.jar ]; then
17 | true
18 | else
19 | echo "Downloading ANTLR 3.2 JAR from http://www.antlr.org/download.html"
20 | curl "http://www.antlr.org/download/antlr-runtime-3.2.jar" > lib/antlr-runtime-3.2.jar || \
21 | (echo "Failed to download ANTLR Runtime. Aborting.";rm -f lib/antlr-runtime-3.2.jar;exit 1)
22 | fi
23 |
24 | if [ -e lib/commons-cli-1.2.jar ]; then
25 | true
26 | else
27 | echo "Downloading Apache Common Cli JAR from http://commons.apache.org/cli/download_cli.cgi"
28 | curl "http://www.us.apache.org/dist//commons/cli/binaries/commons-cli-1.2-bin.tar.gz" | tar -zxf - commons-cli-1.2/commons-cli-1.2.jar -O > lib/commons-cli-1.2.jar || \
29 | (echo "Failed to download Apache Common Cli. Aborting.";rm -f lib/commons-cli-1.2.jar;exit 1)
30 | fi
31 |
32 | if [ -e lib/guava-13.0.1.jar ]; then
33 | true
34 | else
35 | echo "Downloading Google Guava 1.3 JAR from http://code.google.com/p/guava-libraries/wiki/Release13"
36 | curl "http://search.maven.org/remotecontent?filepath=com/google/guava/guava/13.0.1/guava-13.0.1.jar" > lib/guava-13.0.1.jar || \
37 | (echo "Failed to download Google Guava. Aborting.";rm -f lib/guava-13.0.1.jar;exit 1)
38 | fi
39 |
40 | echo "Type 'make' to build the sample parser."
41 |
--------------------------------------------------------------------------------
/dsl/ProtoLexer.g:
--------------------------------------------------------------------------------
1 | // Compatibility with Protocol Buffer defines
2 | // https://developers.google.com/protocol-buffers/docs/proto
3 | lexer grammar ProtoLexer;
4 |
5 | @header {
6 | package dsl;
7 |
8 | import com.google.common.collect.*;
9 | import java.util.Map;
10 | }
11 |
12 | @members {
13 | private static Map literals = HashBiMap.create();
14 | static {
15 | literals.put("PACKAGE_LITERAL", "package");
16 | literals.put("IMPORT_LITERAL", "import");
17 | literals.put("OPTION_LITERAL", "option");
18 | literals.put("ENUM_LITERAL", "enum");
19 | literals.put("MESSAGE_LITERAL", "message");
20 | literals.put("EXTEND_LITERAL", "extend");
21 | literals.put("EXTENSIONS_DEF_LITERAL", "extensions");
22 | literals.put("EXTENSIONS_TO_LITERAL", "to");
23 | literals.put("EXTENSIONS_MAX_LITERAL", "max");
24 | literals.put("SERVICE_LITERAL", "service");
25 | literals.put("RETURNS_LITERAL", "returns");
26 | literals.put("RPC_LITERAL", "rpc");
27 | literals.put("BLOCK_OPEN", "{");
28 | literals.put("BLOCK_CLOSE", "}");
29 | literals.put("PAREN_OPEN", "(");
30 | literals.put("PAREN_CLOSE", ")");
31 | literals.put("BRACKET_OPEN", "[");
32 | literals.put("BRACKET_CLOSE", "]");
33 | literals.put("EQUALS", "=");
34 | literals.put("COLON", ":");
35 | literals.put("COMMA", ",");
36 | literals.put("ITEM_TERMINATOR", ";");
37 | }
38 |
39 | public static Map getLiterals() {
40 | return literals;
41 | }
42 | }
43 |
44 | COMMENT
45 | : '//' ~('\n' | '\r')* END_OF_LINE {skip();}
46 | | '/*' (options {greedy=false;} : .)* '*/' {skip();}
47 | ;
48 | fragment END_OF_LINE: '\r\n' | '\n' | '\r' | {skip();};
49 | WHITESPACE : ('\t' | ' ' | '\r' | '\n' | '\u000C')+ {skip();};
50 |
51 | PACKAGE_LITERAL : 'package' ;
52 | IMPORT_LITERAL : 'import' ;
53 | OPTION_LITERAL : 'option' ;
54 |
55 | ENUM_LITERAL : 'enum' ;
56 | MESSAGE_LITERAL : 'message' ;
57 | EXTEND_LITERAL : 'extend' ;
58 | EXTENSIONS_DEF_LITERAL : 'extensions' ;
59 | EXTENSIONS_TO_LITERAL : 'to' ;
60 | EXTENSIONS_MAX_LITERAL : 'max' ;
61 |
62 | //GROUP_LITERAL : 'group' ; // deprecated
63 | //OPTIONAL_DEFAULT_LITERAL : 'default' ;
64 | //OPTIONAL_DEPRECATED_LITERAL : 'deprecated' ;
65 | //REPEATED_PACKED_LITERAL : 'packed' ;
66 |
67 | SERVICE_LITERAL : 'service' ;
68 | RETURNS_LITERAL : 'returns' ;
69 | RPC_LITERAL : 'rpc' ;
70 |
71 | BLOCK_OPEN : '{' ;
72 | BLOCK_CLOSE : '}' ;
73 | PAREN_OPEN : '(' ;
74 | PAREN_CLOSE : ')' ;
75 | BRACKET_OPEN : '[' ;
76 | BRACKET_CLOSE : ']' ;
77 | EQUALS : '=' ;
78 | COLON : ':' ;
79 | COMMA : ',' ;
80 | ITEM_TERMINATOR : ';' ;
81 |
82 | // Protobuf Scope ---------------------
83 | PROTOBUF_SCOPE_LITERAL
84 | : REQUIRED_PROTOBUF_SCOPE_LITERAL
85 | | OPTIONAL_PROTOBUF_SCOPE_LITERAL
86 | | REPEATED_PROTOBUF_SCOPE_LITERAL
87 | ;
88 |
89 | fragment REQUIRED_PROTOBUF_SCOPE_LITERAL : 'required' ;
90 | fragment OPTIONAL_PROTOBUF_SCOPE_LITERAL : 'optional' ;
91 | fragment REPEATED_PROTOBUF_SCOPE_LITERAL : 'repeated' ;
92 | // Protobuf Scope ---------------------
93 |
94 | // Protobuf Type ----------------------
95 | PROTOBUF_TYPE_LITERAL
96 | : DOUBLE_PROTOBUF_TYPE_LITERAL
97 | | FLOAT_PROTOBUF_TYPE_LITERAL
98 | | INT32_PROTOBUF_TYPE_LITERAL
99 | | INT64_PROTOBUF_TYPE_LITERAL
100 | | UINT32_PROTOBUF_TYPE_LITERAL
101 | | UINT64_PROTOBUF_TYPE_LITERAL
102 | | SINT32_PROTOBUF_TYPE_LITERAL
103 | | SINT64_PROTOBUF_TYPE_LITERAL
104 | | FIXED32_PROTOBUF_TYPE_LITERAL
105 | | FIXED64_PROTOBUF_TYPE_LITERAL
106 | | SFIXED32_PROTOBUF_TYPE_LITERAL
107 | | SFIXED64_PROTOBUF_TYPE_LITERAL
108 | | BOOL_PROTOBUF_TYPE_LITERAL
109 | | STRING_PROTOBUF_TYPE_LITERAL
110 | | BYTES_PROTOBUF_TYPE_LITERAL
111 | ;
112 |
113 | fragment DOUBLE_PROTOBUF_TYPE_LITERAL : 'double' ;
114 | fragment FLOAT_PROTOBUF_TYPE_LITERAL : 'float' ;
115 | fragment INT32_PROTOBUF_TYPE_LITERAL : 'int32' ;
116 | fragment INT64_PROTOBUF_TYPE_LITERAL : 'int64' ;
117 | fragment UINT32_PROTOBUF_TYPE_LITERAL : 'uint32' ;
118 | fragment UINT64_PROTOBUF_TYPE_LITERAL : 'uint64' ;
119 | fragment SINT32_PROTOBUF_TYPE_LITERAL : 'sint32' ;
120 | fragment SINT64_PROTOBUF_TYPE_LITERAL : 'sint64' ;
121 | fragment FIXED32_PROTOBUF_TYPE_LITERAL : 'fixed32' ;
122 | fragment FIXED64_PROTOBUF_TYPE_LITERAL : 'fixed64' ;
123 | fragment SFIXED32_PROTOBUF_TYPE_LITERAL : 'sfixed32' ;
124 | fragment SFIXED64_PROTOBUF_TYPE_LITERAL : 'sfixed64' ;
125 | fragment BOOL_PROTOBUF_TYPE_LITERAL : 'bool' ;
126 | fragment STRING_PROTOBUF_TYPE_LITERAL : 'string' ;
127 | fragment BYTES_PROTOBUF_TYPE_LITERAL : 'bytes' ;
128 | // Protobuf Type ----------------------
129 |
130 | // Integer ----------------------------
131 | INTEGER_LITERAL
132 | : HEX_LITERAL
133 | | OCTAL_LITERAL
134 | | DECIMAL_LITERAL
135 | ;
136 | fragment HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;
137 | fragment HEX_LITERAL : '-'? '0' ('x'|'X') HEX_DIGIT+ ;
138 | fragment OCTAL_LITERAL : '-'? '0' ('0'..'7')+ ;
139 | fragment DECIMAL_LITERAL : ('0' | '-'? '1'..'9' '0'..'9'*) ;
140 | // Integer ----------------------------
141 |
142 | // String -----------------------------
143 | STRING_LITERAL
144 | : '"' STRING_GUTS '"'
145 | ;
146 | fragment STRING_GUTS : ( ESCAPE_SEQUENCE | ~('\\'|'"'|'\n'|'\r') )* ;
147 |
148 | fragment ESCAPE_SEQUENCE
149 | : '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
150 | | OCTAL_ESCAPE
151 | | UNICODE_ESCAPE
152 | ;
153 |
154 | fragment OCTAL_ESCAPE
155 | : '\\' ('0'..'3') ('0'..'7') ('0'..'7')
156 | | '\\' ('0'..'7') ('0'..'7')
157 | | '\\' ('0'..'7')
158 | ;
159 |
160 | fragment UNICODE_ESCAPE
161 | : '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
162 | ;
163 | // String -----------------------------
164 |
165 | // Bool -------------------------------
166 | BOOL_LITERAL : 'true' | 'false';
167 | // Bool -------------------------------
168 |
169 | // Float-------------------------------
170 | FLOAT_LITERAL
171 | : '-'? ('0'..'9')+ '.' ('0'..'9')* EXPONENT?
172 | | '-'? '.' ('0'..'9')+ EXPONENT?
173 | | '-'? ('0'..'9')+ EXPONENT
174 | ;
175 |
176 | fragment EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;
177 | // Float-------------------------------
178 |
179 | IDENTIFIER : '_'* ('a'..'z' | 'A'..'Z' ) ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')* ;
180 | QUALIFIED_IDENTIFIER : IDENTIFIER ('.' IDENTIFIER)+ ;
181 | FIELD_IDENTIFIER : '.' IDENTIFIER ;
182 |
--------------------------------------------------------------------------------
/dsl/ProtoParser.g:
--------------------------------------------------------------------------------
1 | parser grammar ProtoParser;
2 |
3 | options {
4 | output = AST;
5 | language = Java;
6 | tokenVocab = ProtoLexer; // ProtoLexer.tokens
7 | ASTLabelType = CommonTree;
8 | }
9 |
10 | tokens {
11 | PROTO;
12 | OPTION_PREDEFINED;
13 | OPTION_CUSTOMIZED;
14 | OPTION_VALUE_ITEM;
15 | OPTION_VALUE_OBJECT;
16 | ENUM_FIELD;
17 | MESSAGE_FIELD;
18 | }
19 |
20 | @header {
21 | package dsl;
22 | }
23 |
24 | // Predefines
25 | all_identifier
26 | : IDENTIFIER
27 | | QUALIFIED_IDENTIFIER
28 | ;
29 |
30 | all_value
31 | : IDENTIFIER
32 | | literal_value
33 | ;
34 |
35 | literal_value
36 | : INTEGER_LITERAL
37 | | STRING_LITERAL
38 | | BOOL_LITERAL
39 | | FLOAT_LITERAL
40 | ;
41 |
42 | proto_type
43 | : PROTOBUF_TYPE_LITERAL
44 | | all_identifier
45 | ;
46 |
47 | // Proto ------------------------------
48 | proto
49 | : (package_def | import_def | option_line_def | enum_def | ext_def | message_def | service_def)* EOF // Only one package define is allowed - will handle that in the compiler
50 | -> ^(PROTO package_def* import_def* option_line_def* enum_def* ext_def* message_def* service_def*)
51 | ;
52 | // Proto ------------------------------
53 |
54 | // Package ----------------------------
55 | package_def
56 | : PACKAGE_LITERAL package_name ITEM_TERMINATOR
57 | -> ^(PACKAGE_LITERAL package_name)
58 | ;
59 |
60 | package_name : all_identifier ;
61 | // Package ----------------------------
62 |
63 | // Import -----------------------------
64 | import_def
65 | : IMPORT_LITERAL import_file_name ITEM_TERMINATOR
66 | -> ^(IMPORT_LITERAL import_file_name)
67 | ;
68 |
69 | import_file_name : STRING_LITERAL ;
70 | // Import -----------------------------
71 |
72 | // Option in line----------------------
73 | option_line_def
74 | : OPTION_LITERAL option_name EQUALS option_all_value ITEM_TERMINATOR
75 | -> ^(OPTION_LITERAL option_name option_all_value)
76 | ;
77 |
78 | option_field_def
79 | : BRACKET_OPEN! option_field_item (COMMA! option_field_item)* BRACKET_CLOSE!
80 | ;
81 |
82 | option_field_item
83 | : option_name EQUALS option_all_value
84 | -> ^(OPTION_LITERAL option_name option_all_value)
85 | ;
86 |
87 | option_all_value
88 | : all_value
89 | | option_value_object
90 | ;
91 |
92 | option_value_object
93 | : BLOCK_OPEN option_value_item* BLOCK_CLOSE
94 | -> ^(OPTION_VALUE_OBJECT option_value_item*)
95 | ;
96 |
97 | option_value_item
98 | : IDENTIFIER COLON option_all_value
99 | -> ^(OPTION_VALUE_ITEM IDENTIFIER option_all_value)
100 | ;
101 |
102 | option_name
103 | : IDENTIFIER
104 | -> ^(OPTION_PREDEFINED IDENTIFIER)
105 | | PAREN_OPEN all_identifier PAREN_CLOSE FIELD_IDENTIFIER*
106 | -> ^(OPTION_CUSTOMIZED all_identifier FIELD_IDENTIFIER*)
107 | ;
108 | // Option in line----------------------
109 |
110 | // Enum -------------------------------
111 | enum_def
112 | : ENUM_LITERAL enum_name BLOCK_OPEN enum_content BLOCK_CLOSE
113 | -> ^(ENUM_LITERAL enum_name enum_content)
114 | ;
115 |
116 | enum_name : IDENTIFIER ;
117 |
118 | enum_content : (option_line_def | enum_item_def)* ;
119 |
120 | enum_item_def
121 | : IDENTIFIER EQUALS INTEGER_LITERAL option_field_def? ITEM_TERMINATOR
122 | -> ^(ENUM_FIELD IDENTIFIER INTEGER_LITERAL option_field_def?)
123 | ;
124 | // Enum -------------------------------
125 |
126 | // Message ----------------------------
127 | message_def
128 | : MESSAGE_LITERAL message_name BLOCK_OPEN message_content? BLOCK_CLOSE
129 | -> ^(MESSAGE_LITERAL message_name message_content?)
130 | ;
131 |
132 | message_name : IDENTIFIER ;
133 |
134 | message_content : (option_line_def | message_item_def | message_def | enum_def | message_ext_def)+ ;
135 |
136 | message_item_def
137 | : PROTOBUF_SCOPE_LITERAL proto_type IDENTIFIER EQUALS INTEGER_LITERAL option_field_def? ITEM_TERMINATOR
138 | -> ^(MESSAGE_FIELD PROTOBUF_SCOPE_LITERAL proto_type IDENTIFIER INTEGER_LITERAL option_field_def?)
139 | ;
140 |
141 | message_ext_def
142 | : EXTENSIONS_DEF_LITERAL INTEGER_LITERAL EXTENSIONS_TO_LITERAL (v=INTEGER_LITERAL | v=EXTENSIONS_MAX_LITERAL) ITEM_TERMINATOR
143 | -> ^(EXTENSIONS_DEF_LITERAL INTEGER_LITERAL $v)
144 | ;
145 | // Message ----------------------------
146 |
147 | // Extension --------------------------
148 | ext_def
149 | : EXTEND_LITERAL ext_name BLOCK_OPEN ext_content? BLOCK_CLOSE
150 | -> ^(EXTEND_LITERAL ext_name ext_content?)
151 | ;
152 |
153 | ext_name : all_identifier ;
154 |
155 | ext_content : (option_line_def | message_item_def | message_def | enum_def)+ ;
156 | // Extension --------------------------
157 |
158 | // Service ----------------------------
159 | service_def
160 | : SERVICE_LITERAL service_name BLOCK_OPEN service_content? BLOCK_CLOSE
161 | -> ^(SERVICE_LITERAL service_name service_content?)
162 | ;
163 |
164 | service_name : IDENTIFIER ;
165 |
166 | service_content : (option_line_def | rpc_def )+ ;
167 |
168 | rpc_def
169 | : RPC_LITERAL rpc_name PAREN_OPEN req_name PAREN_CLOSE RETURNS_LITERAL PAREN_OPEN resp_name PAREN_CLOSE (BLOCK_OPEN option_line_def* BLOCK_CLOSE ITEM_TERMINATOR? | ITEM_TERMINATOR)
170 | -> ^(RPC_LITERAL rpc_name req_name resp_name option_line_def*)
171 | ;
172 |
173 | rpc_name : IDENTIFIER ;
174 | req_name : all_identifier ;
175 | resp_name : all_identifier ;
176 | // Service ----------------------------
177 |
--------------------------------------------------------------------------------
/protos/bases.proto:
--------------------------------------------------------------------------------
1 | // TEST: package - qualified
2 | package mypack.bases;
3 |
4 | // TEST: name resolution
5 | message AmbiguousMsg {
6 | optional string mypack_bases_msg = 1;
7 | }
8 |
9 | enum AmbiguousEnum {
10 | mypack_bases_enum = 0;
11 | }
12 |
13 | // TEST: scopes
14 | message MyRequest {
15 | required string frequired = 1;
16 | optional string foptional = 2;
17 | repeated string frepeated = 3;
18 |
19 | extensions 100 to 200;
20 | }
21 |
22 | // TEST: name resolution
23 | message MyResponse {
24 | optional AmbiguousMsg fmypack_bases_msg = 1;
25 | optional AmbiguousEnum fmypack_bases_enum = 2;
26 |
27 | extensions 100 to max;
28 | }
--------------------------------------------------------------------------------
/protos/main.proto:
--------------------------------------------------------------------------------
1 | // Follow the language guide and style guide:
2 | // https://developers.google.com/protocol-buffers/docs/proto
3 | // https://developers.google.com/protocol-buffers/docs/style
4 |
5 | // TEST: line comment
6 | /* TEST: block comment cross multiline
7 | */
8 | // TEST: nested line comment (outer) // TEST: nested line comment (inner)
9 | /* TEST: nested block comment (outer)
10 | // TEST: nested line comment (inner)
11 | */
12 | // TEST: nested line comment (outer) /* TEST: nested block comment (inner) */
13 |
14 | // TEST: package
15 | package mypack;
16 | /*
17 | // FAILTEST: multiple packages
18 | package mypack.some_else;
19 | */
20 |
21 | // TEST: imports with -I parameter
22 | import "google/protobuf/descriptor.proto";
23 | import "options.proto";
24 | import "bases.proto";
25 | import "messages.proto";
26 | import "services.proto";
27 |
28 | /*
29 | // FAILTEST: imports nonexist
30 | import "nonexist.proto";
31 | */
32 |
33 | option (mypack.options.myfile_enum) = zero;
34 | option (mypack.options.myfile_ref) = "reference";
35 |
--------------------------------------------------------------------------------
/protos/messages.proto:
--------------------------------------------------------------------------------
1 | // TEST: package - qualified
2 | package mypack.messages;
3 |
4 | import "google/protobuf/descriptor.proto";
5 | import "options.proto";
6 | import "bases.proto";
7 |
8 | // TEST: name resolution
9 | message AmbiguousMsg {
10 | optional string mypack_ambiguous_msg = 1;
11 | }
12 |
13 | enum AmbiguousEnum {
14 | mypack_ambiguous_enum = 0;
15 | }
16 |
17 | message ExplicitMsg {
18 | optional string mypack_explicit_msg = 1;
19 | }
20 |
21 | enum ExplicitEnum {
22 | mypack_explicit_enum = 0;
23 | }
24 |
25 | // TEST: entension, new resolution
26 | extend mypack.bases.MyResponse {
27 | optional AmbiguousMsg fmypack_msg = 101;
28 | optional AmbiguousEnum fmypack_enum = 102;
29 | optional mypack.bases.AmbiguousMsg fmypack_bases_remote_msg = 201;
30 | optional mypack.bases.AmbiguousEnum fmypack_bases_remote_enum = 202;
31 | }
32 |
33 | // TEST: message names
34 | message NameMessage {} // start with higher case
35 | message nameMessage {} // start with lower case
36 | message _nameMessage {} // start with under
37 | message Name_message {} // distinguish under
38 | message N0meMessage {} // contain number
39 | message namemessage {} // all lower case
40 | message NAMEMESSAGE {} // all higher case
41 |
42 | // TEST: enum names
43 | enum NameEnum {
44 | NameEnumValue = 0;
45 | }
46 | enum nameEnum {
47 | nameEnumValue = 0;
48 | }
49 | enum _nameEnum {
50 | _nameEnumValue = 0;
51 | }
52 | enum Name_enum {
53 | Name_enumValue = 0;
54 | }
55 | enum N0meEnum {
56 | N0meEnumValue = 0;
57 | }
58 | enum nameenum {
59 | nameenumvalue = 0;
60 | }
61 | enum NAMEENUM {
62 | NAMEENUMVALUE = 0;
63 | }
64 |
65 | // TEST: message
66 | message OutterMsg {
67 | optional string outter_msg = 1;
68 | }
69 |
70 | enum OutterEnum {
71 | // TEST: enum_option - customized
72 | option (mypack.options.myenum_uint32) = 4294967295;
73 | option (mypack.options.myenum_uint64) = 18446744073709551615;
74 | //option (mypack.options.myenum_message.ffloat) = 1.0; // Not supported
75 | option (mypack.options.myenum_message) = {fsub : {frequired: "[method option][sub message]: required" foptional: "[method option][sub message]: optional"}};
76 | outter_enum = 0;
77 | // TEST: enum_value - customized
78 | outter_enum_option1 = 1 [(mypack.options.myenumvalue_sint32) = -2147483648];
79 | outter_enum_option2 = 2 [(mypack.options.myenumvalue_sint64) = -9223372036854775808];
80 | outter_enum_option3 = 3 [(mypack.options.myenumvalue_message).ffloat = 0.5, (mypack.options.myenumvalue_message).fdouble = 2.0];
81 | }
82 |
83 | message MyMessage {
84 | // TEST: field names
85 | optional string NameField = 1;
86 | optional string nameField = 2;
87 | optional string _nameField = 3;
88 | optional string Name_field = 4;
89 | optional string N0meField = 5;
90 | optional string namefield = 6;
91 | optional string NAMEFIELD = 7;
92 |
93 | // TEST: message types and default value
94 | optional double fdouble = 101 [default = 1.7E-308]; // (-1.7E-308, 1.7E308)
95 | optional float ffloat = 102 [default = -3.4E38]; // ( -3.4E-38, 3.4E38)
96 | optional int32 fint32 = 103 [default = 0x32B]; // HEX
97 | optional int64 fint64 = 104 [default = -064]; // OCTAL
98 | optional uint32 fuint32 = 105 [default = 4294967295]; // (0, 4294967295)
99 | optional uint64 fuint64 = 106 [default = 18446744073709551615]; // (0, 18446744073709551615)
100 | optional sint32 fsint32 = 107 [default = -2147483648]; // (-2147483648, 2147483647)
101 | optional sint64 fsint64 = 108 [default = -9223372036854775808]; // (-9223372036854775808, 9223372036854775807)
102 | optional fixed32 ffixed32 = 109 [default = 4294967295]; // (0, 4294967295)
103 | optional fixed64 ffixed64 = 110 [default = 18446744073709551615]; // (0, 18446744073709551615)
104 | optional sfixed32 fsfixed32 = 111 [default = 2147483647]; // (-2147483648, 2147483647)
105 | optional sfixed64 fsfixed64 = 112 [default = 9223372036854775807]; // (-9223372036854775808, 9223372036854775807)
106 | optional bool fbool = 113 [default = true];
107 | optional string fstring = 114 [default = "ascii str, octal \\163\\164\\162, hex \\u0073\\u0074\\u0072"];
108 | optional bytes fbytes = 115 [default = "bytes"];
109 |
110 | // TEST: float/double format
111 | optional float ffformat1 = 116 [default = 1.2e13];
112 | optional float ffformat2 = 117 [default = -1.2e13];
113 | optional float ffformat3 = 118 [default = 1.2e-13];
114 | optional float ffformat4 = 119 [default = -1.2e-13];
115 | optional float ffformat5 = 120 [default = 1];
116 | optional float ffformat6 = 121 [default = 1.23];
117 | optional float ffformat7 = 122 [default = -1.2];
118 | optional float ffformat8 = 123 [default = .012];
119 | optional float ffformat9 = 124 [default = -.01];
120 |
121 | message NestedMsg {
122 | optional string nested_msg = 1;
123 | }
124 |
125 | enum NestedEnum {
126 | nested_enum = 0;
127 | }
128 |
129 | optional NestedMsg fnested_msg = 201;
130 | optional NestedEnum fnested_enum = 202;
131 | optional OutterMsg foutter_msg = 203;
132 | optional OutterEnum foutter_enum = 204;
133 |
134 | // TEST: message_option - predefined
135 | option message_set_wire_format = false;
136 | // TEST: message_option - customized
137 | option (mypack.options.mymessage_double) = 1.7E308;
138 | option (mypack.options.mymessage_float) = -3.4E-38;
139 | option (mypack.options.mymessage_message).fsub = {frequired: "[method option][sub message]: required" foptional: "[method option][sub message]: optional"};
140 | // TEST: field - predefined
141 | optional string ffield_option_deprecated = 301 [deprecated = false];
142 | repeated double ffield_option_packed = 302 [packed = true];
143 | // TEST: field_option - customized
144 | optional string ffield_option_customized1 = 303 [(mypack.options.myfield_int32) = 0x32B];
145 | optional string ffield_option_customized2 = 304 [(mypack.options.myfield_int64) = -064];
146 | optional string ffield_option_customized3 = 305 [(mypack.options.myfield_message) = {ffloat: .01 fdouble: -0.1}];
147 | }
148 |
--------------------------------------------------------------------------------
/protos/options.proto:
--------------------------------------------------------------------------------
1 | // Follow the language guide and style guide:
2 | // https://developers.google.com/protocol-buffers/docs/proto
3 | // https://developers.google.com/protocol-buffers/docs/style
4 |
5 | // TEST: package - qualified
6 | package mypack.options;
7 |
8 | import "google/protobuf/descriptor.proto";
9 |
10 | enum OptionEnum {
11 | zero = 0;
12 | ONE = 1;
13 | Two = 2;
14 | _three = 3;
15 | TWENTY_ONE = 21;
16 | }
17 |
18 | message SubOptionMessage {
19 | required string frequired = 1;
20 | optional string foptional = 2;
21 | //repeated string frepeated = 3; // repeated options are not supported.
22 | }
23 |
24 | message OptionMessage {
25 | optional double fdouble = 1;
26 | optional float ffloat = 2;
27 | optional int32 fint32 = 3;
28 | optional int64 fint64 = 4;
29 | optional uint32 fuint32 = 5;
30 | optional uint64 fuint64 = 6;
31 | optional sint32 fsint32 = 7;
32 | optional sint64 fsint64 = 8;
33 | optional fixed32 ffixed32 = 9;
34 | optional fixed64 ffixed64 = 10;
35 | optional sfixed32 fsfixed32 = 11;
36 | optional sfixed64 fsfixed64 = 12;
37 | optional bool fbool = 13;
38 | optional string fstring = 14;
39 | optional bytes fbytes = 15;
40 | optional SubOptionMessage fsub = 16;
41 | }
42 |
43 | // TEST: FileOptions
44 | extend google.protobuf.FileOptions {
45 | optional bool myfile_bool = 9527;
46 | optional string myfile_string = 9528;
47 | optional bytes myfile_bytes = 9529;
48 | optional string myfile_ref = 9530;
49 | optional OptionMessage myfile_message = 9531;
50 | optional OptionEnum myfile_enum = 9532;
51 | }
52 |
53 | // TEST: MessageOptions
54 | extend google.protobuf.MessageOptions {
55 | optional double mymessage_double = 9527;
56 | optional float mymessage_float = 9528;
57 | optional OptionMessage mymessage_message = 9529;
58 | }
59 |
60 | // TEST: FieldOptions
61 | extend google.protobuf.FieldOptions {
62 | optional int32 myfield_int32 = 9527;
63 | optional int64 myfield_int64 = 9528;
64 | optional OptionMessage myfield_message = 9529;
65 | }
66 |
67 | // TEST: EnumOptions
68 | extend google.protobuf.EnumOptions {
69 | optional uint32 myenum_uint32 = 9527;
70 | optional uint64 myenum_uint64 = 9528;
71 | optional OptionMessage myenum_message = 9529;
72 | }
73 |
74 | // TEST: EnumValueOptions
75 | extend google.protobuf.EnumValueOptions {
76 | optional sint32 myenumvalue_sint32 = 9527;
77 | optional sint64 myenumvalue_sint64 = 9528;
78 | optional OptionMessage myenumvalue_message = 9529;
79 | }
80 |
81 | // TEST: ServiceOptions
82 | extend google.protobuf.ServiceOptions {
83 | optional fixed32 myservice_fixed32 = 9527;
84 | optional fixed64 myservice_fixed64 = 9528;
85 | optional OptionMessage myservice_message = 9529;
86 | }
87 |
88 | // TEST: MethodOptions
89 | extend google.protobuf.MethodOptions {
90 | optional sfixed32 mymethod_sfixed32 = 9527;
91 | optional sfixed64 mymethod_sfixed64 = 9528;
92 | optional OptionMessage mymethod_message = 9529;
93 | }
94 |
95 | // TEST: file_option - predefined
96 | option optimize_for = SPEED;
97 | option cc_generic_services = false;
98 |
99 | // TEST: file_option - customized
100 | option (myfile_message).fdouble = 1.7E-308;
101 | option (myfile_message).ffloat = -3.4E38;
102 | option (myfile_message).fint32 = 0x32B;
103 | option (myfile_message).fint64 = -064;
104 | option (myfile_message).fuint32 = 4294967295;
105 | option (myfile_message).fuint64 = 18446744073709551615;
106 | option (myfile_message).fsint32 = -2147483648;
107 | option (myfile_message).fsint64 = -9223372036854775808;
108 | option (myfile_message).ffixed32 = 4294967295;
109 | option (myfile_message).ffixed64 = 18446744073709551615;
110 | option (myfile_message).fsfixed32 = 2147483647;
111 | option (myfile_message).fsfixed64 = 9223372036854775807;
112 | option (myfile_message).fbool = false;
113 | option (myfile_message).fstring = "ascii str, octal \\163\\164\\162, hex \\u0073\\u0074\\u0072";
114 | option (myfile_message).fbytes = "bytes";
115 | option (myfile_message).fsub.frequired = "[file option][sub message]: required";
116 | option (myfile_message).fsub.foptional = "[file option][sub message]: optional";
117 | option (myfile_bool) = false;
118 | option (myfile_string) = "string";
119 | option (myfile_bytes) = "bytes";
120 |
--------------------------------------------------------------------------------
/protos/services.proto:
--------------------------------------------------------------------------------
1 | // TEST: package - qualified
2 | package mypack.services;
3 |
4 | import "google/protobuf/descriptor.proto";
5 | import "options.proto";
6 | import "bases.proto";
7 | import "messages.proto";
8 |
9 | // TEST: service names
10 | service NameService {} // start with higher case
11 | service nameService {} // start with lower case
12 | service _nameService {} // start with under
13 | service Name_service {} // distinguish under
14 | service N0meService {} // contain number
15 | service nameservice {} // all lower case
16 | service NAMESERVICE {} // all higher case
17 |
18 | // TEST: method names
19 | service DummyService {
20 | rpc NameMethod (LocalRequest) returns (LocalResponse);
21 | rpc nameMethod (LocalRequest) returns (LocalResponse);
22 | rpc _nameMethod (LocalRequest) returns (LocalResponse);
23 | rpc Name_method (LocalRequest) returns (LocalResponse);
24 | rpc N0meMethod (LocalRequest) returns (LocalResponse);
25 | rpc namemethod (LocalRequest) returns (LocalResponse);
26 | rpc NAMEMETHOD (LocalRequest) returns (LocalResponse);
27 | }
28 |
29 | // TEST: service
30 | message LocalRequest {}
31 | message LocalResponse {}
32 |
33 | service MyService {
34 | // TEST: service_option - customized
35 | option (mypack.options.myservice_fixed32) = 4294967295;
36 | option (mypack.options.myservice_fixed64) = 18446744073709551615;
37 |
38 | rpc LocalCall (LocalRequest) returns (LocalResponse) {
39 | option (mypack.options.mymethod_sfixed32) = 2147483647;
40 | option (mypack.options.mymethod_sfixed64) = 9223372036854775807;
41 | }
42 |
43 | rpc RemoteCall (mypack.bases.MyRequest) returns (mypack.bases.MyResponse);
44 | }
45 |
--------------------------------------------------------------------------------
/sampleparser/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Main-Class: sampleparser.SampleParser
2 | Class-Path: lib/antlr-runtime-3.2.jar lib/commons-cli-1.2.jar lib/guava-13.0.1.jar
3 |
--------------------------------------------------------------------------------
/sampleparser/SampleExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package sampleparser;
2 |
3 | import org.antlr.runtime.*;
4 | import java.util.Map;
5 |
6 | public class SampleExceptionHandler {
7 | private boolean isLexer;
8 | private String fname;
9 | private String[] tokenNames;
10 | private Map literalNames;
11 |
12 | public SampleExceptionHandler(String fname, Map literalNames, String[] tokenNames, boolean isLexer) {
13 | this.fname = fname;
14 | this.literalNames = literalNames;
15 | this.tokenNames = tokenNames;
16 | this.isLexer = isLexer;
17 | }
18 |
19 | private String handleMismatchedToken(MismatchedTokenException e) {
20 | if (isLexer) {
21 | return String.format("Unexpected input '%c'.", e.c);
22 | } else {
23 | if (e.expecting == Token.EOF) {
24 | return String.format("Unexpected input '%s' - 'package', 'import', 'option', 'enum', 'message', 'extend', 'server' is expected.", e.token.getText());
25 | }
26 | String expecting = tokenNames[e.expecting];
27 | if (literalNames.containsKey(expecting)) {
28 | expecting = (String) literalNames.get(expecting);
29 | }
30 | return String.format("Unexpected input '%s' - '%s' is expected.", e.token.getText(), expecting);
31 | }
32 | }
33 |
34 | private String handleNoViableAltException(NoViableAltException e) {
35 | if (isLexer) {
36 | return String.format("Unrecognized input '%c'.", e.c);
37 | } else {
38 | return String.format("Unrecognized input '%s'.", e.token.getText());
39 | }
40 | }
41 |
42 | private String handleMismatchedSetException(MismatchedSetException e) {
43 | if (isLexer) {
44 | return String.format("Unexpected input '%c'.", e.c);
45 | } else {
46 | return String.format("Unexpected input '%s'.", e.token.getText());
47 | }
48 | }
49 |
50 | public void handle(String[] tokenNames, RecognitionException e) {
51 | String errorMsg = "";
52 | if (e instanceof EarlyExitException) {
53 | errorMsg = "EarlyExitException";
54 | } else if (e instanceof FailedPredicateException) {
55 | errorMsg = "FailedPredicateException";
56 | } else if (e instanceof MismatchedRangeException) {
57 | errorMsg = "MismatchedRangeException";
58 | } else if (e instanceof MismatchedSetException) {
59 | errorMsg = this.handleMismatchedSetException((MismatchedSetException) e);
60 | } else if (e instanceof MismatchedTokenException) {
61 | errorMsg = this.handleMismatchedToken((MismatchedTokenException) e);
62 | } else if (e instanceof MismatchedTreeNodeException) {
63 | errorMsg = "MismatchedTreeNodeException";
64 | } else if (e instanceof NoViableAltException) {
65 | errorMsg = this.handleNoViableAltException((NoViableAltException) e);
66 | }
67 | System.out.printf("[%s] Line %d: %s\n", this.fname, e.line, errorMsg);
68 | System.exit(1);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/sampleparser/SampleParser.java:
--------------------------------------------------------------------------------
1 | package sampleparser;
2 |
3 | import java.io.IOException;
4 | import org.antlr.runtime.*;
5 | import org.antlr.runtime.tree.*;
6 | import org.apache.commons.cli.*;
7 |
8 | public class SampleParser {
9 | private static boolean showTrace;
10 |
11 | private static void trace(Tree node, int depth) {
12 | for (int i=0; i
2 | 【翻译】ANTLR 3
3 | Memo Maven: ANTLR project
4 | ANTLR笔记4 - AST构造,tree grammar,tree walker
5 | ANTLR3 简介及示例
6 |