├── 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 | --------------------------------------------------------------------------------