blob: 186fb61d63349923a605a78a6f9484b5914f3b56 [file] [log] [blame]
Andreas Huber1aec3972016-08-26 09:26:32 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Andreas Huberc9410c72016-07-28 12:18:40 -070017%{
18
Andreas Huber3599d922016-08-09 10:42:57 -070019#include "Annotation.h"
Andreas Huberc9410c72016-07-28 12:18:40 -070020#include "AST.h"
21#include "ArrayType.h"
22#include "CompoundType.h"
Yifan Hong52165692016-08-12 18:06:40 -070023#include "ConstantExpression.h"
Andreas Huberc9410c72016-07-28 12:18:40 -070024#include "EnumType.h"
Yifan Hongf24fa852016-09-23 11:03:15 -070025#include "FQName.h"
Andreas Huber295ad302016-08-16 11:35:00 -070026#include "GenericBinder.h"
Andreas Huberc9410c72016-07-28 12:18:40 -070027#include "Interface.h"
Yifan Honga4b53d02016-10-31 17:29:10 -070028#include "Location.h"
Andreas Huberc9410c72016-07-28 12:18:40 -070029#include "Method.h"
Andreas Huberc9410c72016-07-28 12:18:40 -070030#include "VectorType.h"
Yifan Hongbf459bc2016-08-23 16:50:37 -070031#include "RefType.h"
Andreas Huberc9410c72016-07-28 12:18:40 -070032
33#include "hidl-gen_y.h"
34
Andreas Huber709b62d2016-09-19 11:21:18 -070035#include <android-base/logging.h>
Yifan Hong27e85db2016-11-09 15:45:52 -080036#include <hidl-util/StringHelper.h>
Andreas Huberc9410c72016-07-28 12:18:40 -070037#include <stdio.h>
38
39using namespace android;
40
Andreas Huber0d0f9a22016-08-17 10:26:11 -070041extern int yylex(yy::parser::semantic_type *, yy::parser::location_type *, void *);
Andreas Huberc9410c72016-07-28 12:18:40 -070042
43#define scanner ast->scanner()
44
Yifan Honga4b53d02016-10-31 17:29:10 -070045::android::Location convertYYLoc(const yy::parser::location_type &loc) {
46 return ::android::Location(
47 ::android::Position(*(loc.begin.filename), loc.begin.line, loc.begin.column),
48 ::android::Position(*(loc.end.filename), loc.end.line, loc.end.column)
49 );
50}
51
Yifan Hong27e85db2016-11-09 15:45:52 -080052bool isValidInterfaceField(const char *identifier, std::string *errorMsg) {
53 static const std::vector<std::string> reserved({
54 // Injected names to interfaces by auto-generated code
55 "isRemote", "interfaceChain", "descriptor", "hidlStaticBlock", "onTransact",
56 "castFrom", "version", "getInterfaceVersion",
57
58 // Inherited names by interfaces from IInterface / IBinder
59 "onAsBinder", "asBinder", "queryLocalInterface", "getInterfaceDescriptor", "isBinderAlive",
60 "pingBinder", "dump", "transact", "linkToDeath", "unlinkToDeath", "checkSubclass",
61 "attachObject", "findObject", "detachObject", "localBinder", "remoteBinder", "mImpl",
62 });
63 std::string idstr(identifier);
64 if (std::find(reserved.begin(), reserved.end(), idstr) != reserved.end()) {
65 *errorMsg = idstr + " cannot be a name inside an interface";
66 return false;
67 }
68 return true;
69}
70
71bool isValidStructField(const char *identifier, std::string *errorMsg) {
72 static const std::vector<std::string> reserved({
73 // Injected names to structs and unions by auto-generated code
74 "readEmbeddedFromParcel", "writeEmbeddedToParcel", "readVectorFromParcel",
75 "writeVectorToParcel", "writeEmbeddedToBlob",
76 });
77 std::string idstr(identifier);
78 if (std::find(reserved.begin(), reserved.end(), idstr) != reserved.end()) {
79 *errorMsg = idstr + " cannot be a name inside an struct or union";
80 return false;
81 }
82 return true;
83}
84
85bool isValidIdentifier(const char *identifier, std::string *errorMsg) {
86 static const std::vector<std::string> keywords({
87 "uint8_t", "uint16_t", "uint32_t", "uint64_t",
88 "int8_t", "int16_t", "int32_t", "int64_t", "bool", "float", "double",
89 "interface", "struct", "union", "string", "vec", "enum", "ref", "handle",
90 "package", "import", "typedef", "generates", "oneway", "extends",
91 "MQDescriptorSync", "MQDescriptorUnsync",
92 });
93 static const std::vector<std::string> cppKeywords({
94 "alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel", "atomic_commit",
95 "atomic_noexcept", "auto", "bitand", "bitor", "bool", "break", "case", "catch",
96 "char", "char16_t", "char32_t", "class", "compl", "concept", "const", "constexpr",
97 "const_cast", "continue", "decltype", "default", "delete", "do", "double",
98 "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", "float",
99 "for", "friend", "goto", "if", "inline", "int", "import", "long", "module", "mutable",
100 "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq",
101 "private", "protected", "public", "register", "reinterpret_cast", "requires", "return",
102 "short", "signed", "sizeof", "static", "static_assert", "static_cast", "struct",
103 "switch", "synchronized", "template", "this", "thread_local", "throw", "true", "try",
104 "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", "void",
105 "volatile", "wchar_t", "while", "xor", "xor_eq",
106 });
107 static const std::vector<std::string> javaKeywords({
108 "abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package",
109 "synchronized", "boolean", "do", "if", "private", "this", "break", "double",
110 "implements", "protected", "throw", "byte", "else", "import", "public", "throws",
111 "case", "enum", "instanceof", "return", "transient", "catch", "extends", "int",
112 "short", "try", "char", "final", "interface", "static", "void", "class", "finally",
113 "long", "strictfp", "volatile", "const", "float", "native", "super", "while",
114 });
115 static const std::vector<std::string> cppCollide({
116 "size_t", "offsetof",
117 "DECLARE_REGISTER_AND_GET_SERVICE", "IMPLEMENT_HWBINDER_META_INTERFACE",
118 "IMPLEMENT_REGISTER_AND_GET_SERVICE"
119 });
120 static const std::vector<std::string> hidlReserved({
121 // Part of HidlSupport
122 "hidl_string", "hidl_vec", "hidl_array", "hidl_version", "toBinder", "castInterface",
123 "make_hidl_version"
124 });
125
126 // errors
127 std::string idstr(identifier);
128 if (std::find(keywords.begin(), keywords.end(), idstr) != keywords.end()) {
129 *errorMsg = idstr + " is a HIDL keyword "
130 "and is therefore not a valid identifier";
131 return false;
132 }
133 if (std::find(cppKeywords.begin(), cppKeywords.end(), idstr) != cppKeywords.end()) {
134 *errorMsg = idstr + " is a C++ keyword "
135 "and is therefore not a valid identifier";
136 return false;
137 }
138 if (std::find(javaKeywords.begin(), javaKeywords.end(), idstr) != javaKeywords.end()) {
139 *errorMsg = idstr + " is a Java keyword "
140 "and is therefore not a valid identifier";
141 return false;
142 }
143 if (std::find(cppCollide.begin(), cppCollide.end(), idstr) != cppCollide.end()) {
144 *errorMsg = idstr + " collides with reserved names in C++ code "
145 "and is therefore not a valid identifier";
146 return false;
147 }
148 if (StringHelper::StartsWith(idstr, "_hidl_")) {
149 *errorMsg = idstr + " starts with _hidl_ "
150 "and is therefore not a valid identifier";
151 return false;
152 }
153 if (StringHelper::EndsWith(idstr, "_cb")) {
154 *errorMsg = idstr + " ends with _cb "
155 "and is therefore not a valid identifier";
156 return false;
157 }
158
159 // warnings
160 if (std::find(hidlReserved.begin(), hidlReserved.end(), idstr) != hidlReserved.end()) {
161 *errorMsg = idstr + " is a name reserved by HIDL and should be avoided";
162 }
163 return true;
164}
Yifan Honga4b53d02016-10-31 17:29:10 -0700165
Andreas Huberc9410c72016-07-28 12:18:40 -0700166%}
167
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700168%initial-action {
169 // Initialize the initial location.
170 @$.begin.filename = @$.end.filename =
171 const_cast<std::string *>(&ast->getFilename());
172}
173
Andreas Huberc9410c72016-07-28 12:18:40 -0700174%parse-param { android::AST *ast }
175%lex-param { void *scanner }
176%pure-parser
Steven Moreland4ab9b792016-09-26 14:14:07 -0700177%glr-parser
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700178%skeleton "glr.cc"
Andreas Huberc9410c72016-07-28 12:18:40 -0700179
Steven Moreland4ab9b792016-09-26 14:14:07 -0700180%expect-rr 0
181
Andreas Huberc9410c72016-07-28 12:18:40 -0700182%token<str> ENUM
183%token<str> EXTENDS
Andreas Huber84f89de2016-07-28 15:39:51 -0700184%token<str> FQNAME
Andreas Huberc9410c72016-07-28 12:18:40 -0700185%token<str> GENERATES
186%token<str> IDENTIFIER
187%token<str> IMPORT
188%token<str> INTEGER
Yifan Hong52165692016-08-12 18:06:40 -0700189%token<str> FLOAT
Andreas Huberc9410c72016-07-28 12:18:40 -0700190%token<str> INTERFACE
191%token<str> PACKAGE
Hridya Valsarajucd91bf62016-10-25 12:41:04 -0700192%token<type> TYPE
Andreas Huberc9410c72016-07-28 12:18:40 -0700193%token<str> STRUCT
194%token<str> STRING_LITERAL
195%token<str> TYPEDEF
196%token<str> UNION
Yifan Hongbf459bc2016-08-23 16:50:37 -0700197%token<templatedType> TEMPLATED
Iliyan Malchev639bff82016-08-13 14:24:11 -0700198%token<void> ONEWAY
Andreas Huberc9410c72016-07-28 12:18:40 -0700199
Yifan Hong52165692016-08-12 18:06:40 -0700200/* Operator precedence and associativity, as per
201 * http://en.cppreference.com/w/cpp/language/operator_precedence */
202/* Precedence level 15 ternary operator */
203%right '?' ':'
204/* Precedence level 13 - 14, LTR, logical operators*/
205%left LOGICAL_OR
206%left LOGICAL_AND
207/* Precedence level 10 - 12, LTR, bitwise operators*/
208%left '|'
209%left '^'
210%left '&'
211/* Precedence level 9, LTR */
212%left EQUALITY NEQ
213/* Precedence level 8, LTR */
214%left '<' '>' LEQ GEQ
215/* Precedence level 7, LTR */
216%left LSHIFT RSHIFT
217/* Precedence level 6, LTR */
218%left '+' '-'
219/* Precedence level 5, LTR */
220%left '*' '/' '%'
221/* Precedence level 3, RTL; but we have to use %left here */
222%left UNARY_MINUS UNARY_PLUS '!' '~'
223
Yifan Hongbe627b32016-10-28 18:38:56 -0700224%type<str> error_stmt opt_error_stmt error
Yifan Hong6a2fedf2016-10-11 13:44:07 -0700225%type<str> package
Yifan Hongae16eed2016-09-23 13:25:25 -0700226%type<fqName> fqname
227%type<type> fqtype
Yifan Hong27e85db2016-11-09 15:45:52 -0800228%type<str> valid_identifier
Andreas Huberc9410c72016-07-28 12:18:40 -0700229
Steven Moreland1c71fd52016-11-29 14:03:33 -0800230%type<type> type enum_storage_type
Yifan Hongbd33e382016-11-02 13:30:17 -0700231%type<type> array_type_base
232%type<arrayType> array_type
Andreas Huberc9410c72016-07-28 12:18:40 -0700233%type<type> opt_extends
Yifan Hong27e85db2016-11-09 15:45:52 -0800234%type<type> type_declaration type_declaration_body interface_declaration typedef_declaration
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700235%type<type> named_struct_or_union_declaration named_enum_declaration
236%type<type> compound_declaration annotated_compound_declaration
Andreas Huberc9410c72016-07-28 12:18:40 -0700237
238%type<field> field_declaration
239%type<fields> field_declarations struct_or_union_body
Yifan Hong52165692016-08-12 18:06:40 -0700240%type<constantExpression> const_expr
Andreas Huberc9410c72016-07-28 12:18:40 -0700241%type<enumValue> enum_value
Yifan Hongf24fa852016-09-23 11:03:15 -0700242%type<enumValues> enum_values enum_declaration_body
Andreas Huberc9410c72016-07-28 12:18:40 -0700243%type<typedVars> typed_vars
244%type<typedVar> typed_var
245%type<method> method_declaration
246%type<compoundStyle> struct_or_union_keyword
Yifan Hongf24fa852016-09-23 11:03:15 -0700247%type<stringVec> annotation_string_values annotation_string_value
248%type<constExprVec> annotation_const_expr_values annotation_const_expr_value
Andreas Huber3599d922016-08-09 10:42:57 -0700249%type<annotationParam> annotation_param
250%type<annotationParams> opt_annotation_params annotation_params
251%type<annotation> annotation
252%type<annotations> opt_annotations
Andreas Huberc9410c72016-07-28 12:18:40 -0700253
254%start program
255
256%union {
257 const char *str;
258 android::Type *type;
Yifan Hongbd33e382016-11-02 13:30:17 -0700259 android::ArrayType *arrayType;
Yifan Hongbf459bc2016-08-23 16:50:37 -0700260 android::TemplatedType *templatedType;
Yifan Hongae16eed2016-09-23 13:25:25 -0700261 android::FQName *fqName;
Andreas Huberc9410c72016-07-28 12:18:40 -0700262 android::CompoundType *compoundType;
263 android::CompoundField *field;
Andreas Huber881227d2016-08-02 14:20:21 -0700264 std::vector<android::CompoundField *> *fields;
Andreas Huberc9410c72016-07-28 12:18:40 -0700265 android::EnumValue *enumValue;
Yifan Hong52165692016-08-12 18:06:40 -0700266 android::ConstantExpression *constantExpression;
Andreas Huber881227d2016-08-02 14:20:21 -0700267 std::vector<android::EnumValue *> *enumValues;
Andreas Huberc9410c72016-07-28 12:18:40 -0700268 android::TypedVar *typedVar;
Andreas Huber881227d2016-08-02 14:20:21 -0700269 std::vector<android::TypedVar *> *typedVars;
Andreas Huberc9410c72016-07-28 12:18:40 -0700270 android::Method *method;
271 android::CompoundType::Style compoundStyle;
Andreas Huber3599d922016-08-09 10:42:57 -0700272 std::vector<std::string> *stringVec;
Yifan Hongf24fa852016-09-23 11:03:15 -0700273 std::vector<android::ConstantExpression *> *constExprVec;
Steven Morelandd537ab02016-09-12 10:32:01 -0700274 android::AnnotationParam *annotationParam;
275 android::AnnotationParamVector *annotationParams;
Andreas Huber3599d922016-08-09 10:42:57 -0700276 android::Annotation *annotation;
Steven Morelandd537ab02016-09-12 10:32:01 -0700277 std::vector<android::Annotation *> *annotations;
Andreas Huberc9410c72016-07-28 12:18:40 -0700278}
279
280%%
281
Yifan Hong27e85db2016-11-09 15:45:52 -0800282valid_identifier
283 : IDENTIFIER
284 {
285 std::string errorMsg;
286 if (!isValidIdentifier($1, &errorMsg)) {
287 std::cerr << "ERROR: " << errorMsg << " at " << @1 << "\n";
288 YYERROR;
289 }
290 if (!errorMsg.empty()) {
291 std::cerr << "WARNING: " << errorMsg << " at " << @1 << "\n";
292 }
293 $$ = $1;
294 }
295 ;
296
Andreas Huber3599d922016-08-09 10:42:57 -0700297opt_annotations
298 : /* empty */
299 {
Steven Morelandd537ab02016-09-12 10:32:01 -0700300 $$ = new std::vector<Annotation *>;
Andreas Huber3599d922016-08-09 10:42:57 -0700301 }
302 | opt_annotations annotation
303 {
304 $$ = $1;
Steven Morelandd537ab02016-09-12 10:32:01 -0700305 $$->push_back($2);
Andreas Huber3599d922016-08-09 10:42:57 -0700306 }
307 ;
308
309annotation
310 : '@' IDENTIFIER opt_annotation_params
311 {
312 $$ = new Annotation($2, $3);
313 }
314 ;
315
316opt_annotation_params
317 : /* empty */
318 {
Steven Morelandd537ab02016-09-12 10:32:01 -0700319 $$ = new AnnotationParamVector;
Andreas Huber3599d922016-08-09 10:42:57 -0700320 }
321 | '(' annotation_params ')'
322 {
323 $$ = $2;
324 }
325 ;
326
327annotation_params
328 : annotation_param
329 {
Steven Morelandd537ab02016-09-12 10:32:01 -0700330 $$ = new AnnotationParamVector;
331 $$->push_back($1);
Andreas Huber3599d922016-08-09 10:42:57 -0700332 }
333 | annotation_params ',' annotation_param
334 {
335 $$ = $1;
Steven Morelandd537ab02016-09-12 10:32:01 -0700336 $$->push_back($3);
Andreas Huber3599d922016-08-09 10:42:57 -0700337 }
338 ;
339
340annotation_param
Yifan Hongf24fa852016-09-23 11:03:15 -0700341 : IDENTIFIER '=' annotation_string_value
342 {
343 $$ = new AnnotationParam($1, $3);
344 }
345 | IDENTIFIER '=' annotation_const_expr_value
Andreas Huber3599d922016-08-09 10:42:57 -0700346 {
Steven Morelandd537ab02016-09-12 10:32:01 -0700347 $$ = new AnnotationParam($1, $3);
Andreas Huber3599d922016-08-09 10:42:57 -0700348 }
349 ;
350
Yifan Hongf24fa852016-09-23 11:03:15 -0700351annotation_string_value
Andreas Huber3599d922016-08-09 10:42:57 -0700352 : STRING_LITERAL
353 {
354 $$ = new std::vector<std::string>;
355 $$->push_back($1);
356 }
357 | '{' annotation_string_values '}' { $$ = $2; }
358 ;
359
360annotation_string_values
361 : STRING_LITERAL
362 {
363 $$ = new std::vector<std::string>;
364 $$->push_back($1);
365 }
366 | annotation_string_values ',' STRING_LITERAL
367 {
368 $$ = $1;
369 $$->push_back($3);
370 }
371 ;
372
Yifan Hongf24fa852016-09-23 11:03:15 -0700373annotation_const_expr_value
374 : const_expr
375 {
376 $$ = new std::vector<ConstantExpression *>;
377 $$->push_back($1);
378 }
379 | '{' annotation_const_expr_values '}' { $$ = $2; }
380 ;
381
382annotation_const_expr_values
383 : const_expr
384 {
385 $$ = new std::vector<ConstantExpression *>;
386 $$->push_back($1);
387 }
388 | annotation_const_expr_values ',' const_expr
389 {
390 $$ = $1;
391 $$->push_back($3);
392 }
393 ;
394
Yifan Hongbe627b32016-10-28 18:38:56 -0700395error_stmt
396 : error ';'
397 {
398 $$ = $1;
399 ast->addSyntaxError();
400 // std::cerr << "WARNING: skipping errors until " << @2 << ".\n";
401 }
402 ;
403
404opt_error_stmt
405 : /* empty */ { $$ = NULL; }
406 | error_stmt { $$ = $1; }
407 ;
408
409require_semicolon
410 : ';'
411 | /* empty */
412 {
413 std::cerr << "ERROR: missing ; at " << @$ << "\n";
414 ast->addSyntaxError();
415 }
416 ;
417
Andreas Huberc9410c72016-07-28 12:18:40 -0700418program
Yifan Hongbe627b32016-10-28 18:38:56 -0700419 : opt_error_stmt
420 package
421 imports
422 body
Andreas Huber84f89de2016-07-28 15:39:51 -0700423 ;
424
425fqname
426 : FQNAME
427 {
Yifan Hongae16eed2016-09-23 13:25:25 -0700428 $$ = new FQName($1);
429 if(!$$->isValid()) {
430 std::cerr << "ERROR: FQName '" << $1 << "' is not valid at "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700431 << @1
Yifan Hongae16eed2016-09-23 13:25:25 -0700432 << ".\n";
Andreas Huber84f89de2016-07-28 15:39:51 -0700433 YYERROR;
434 }
435 }
Yifan Hong27e85db2016-11-09 15:45:52 -0800436 | valid_identifier
Andreas Huber84f89de2016-07-28 15:39:51 -0700437 {
Yifan Hongae16eed2016-09-23 13:25:25 -0700438 $$ = new FQName($1);
439 if(!$$->isValid()) {
440 std::cerr << "ERROR: FQName '" << $1 << "' is not valid at "
441 << @1
442 << ".\n";
443 YYERROR;
444 }
445 }
446 ;
447
448fqtype
449 : fqname
450 {
451 $$ = ast->lookupType(*($1));
Andreas Huber84f89de2016-07-28 15:39:51 -0700452 if ($$ == NULL) {
Yifan Hongae16eed2016-09-23 13:25:25 -0700453 std::cerr << "ERROR: Failed to lookup type '" << $1->string() << "' at "
454 << @1
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700455 << "\n";
456
Andreas Huber84f89de2016-07-28 15:39:51 -0700457 YYERROR;
458 }
459 }
Hridya Valsarajucd91bf62016-10-25 12:41:04 -0700460 | TYPE
Andreas Huber84f89de2016-07-28 15:39:51 -0700461 ;
Andreas Huberc9410c72016-07-28 12:18:40 -0700462
463package
Yifan Hongbe627b32016-10-28 18:38:56 -0700464 : PACKAGE FQNAME require_semicolon
Andreas Hubereb1081f2016-07-28 13:13:24 -0700465 {
Andreas Huber84f89de2016-07-28 15:39:51 -0700466 if (!ast->setPackage($2)) {
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700467 std::cerr << "ERROR: Malformed package identifier '"
468 << $2
469 << "' at "
470 << @2
471 << "\n";
472
Andreas Huber84f89de2016-07-28 15:39:51 -0700473 YYERROR;
474 }
Andreas Hubereb1081f2016-07-28 13:13:24 -0700475 }
Andreas Huberc9410c72016-07-28 12:18:40 -0700476
Yifan Hongbe627b32016-10-28 18:38:56 -0700477import_stmt
478 : IMPORT FQNAME require_semicolon
479 {
480 if (!ast->addImport($2)) {
481 std::cerr << "ERROR: Unable to import '" << $2 << "' at " << @2
482 << "\n";
483 ast->addSyntaxError();
484 }
485 }
Yifan Hong27e85db2016-11-09 15:45:52 -0800486 | IMPORT valid_identifier require_semicolon
Yifan Hongbe627b32016-10-28 18:38:56 -0700487 {
488 if (!ast->addImport($2)) {
489 std::cerr << "ERROR: Unable to import '" << $2 << "' at " << @2
490 << "\n";
491 ast->addSyntaxError();
492 }
493 }
494 | IMPORT error_stmt
495 ;
496
497
Andreas Huberc9410c72016-07-28 12:18:40 -0700498imports
499 : /* empty */
Yifan Hongbe627b32016-10-28 18:38:56 -0700500 | imports import_stmt
Andreas Huberc9410c72016-07-28 12:18:40 -0700501 ;
502
503opt_extends
504 : /* empty */ { $$ = NULL; }
Yifan Hongae16eed2016-09-23 13:25:25 -0700505 | EXTENDS fqtype { $$ = $2; }
Andreas Huberc9410c72016-07-28 12:18:40 -0700506
507body
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700508 : type_declarations
Andreas Huberc9410c72016-07-28 12:18:40 -0700509 ;
510
511interface_declarations
512 : /* empty */
513 | interface_declarations type_declaration
Yifan Hong27e85db2016-11-09 15:45:52 -0800514 {
515 std::string errorMsg;
516 if ($2 != nullptr &&
517 $2->isNamedType() &&
518 !isValidInterfaceField(static_cast<NamedType *>($2)->localName().c_str(),
519 &errorMsg)) {
520 std::cerr << "ERROR: " << errorMsg << " at "
521 << @2 << "\n";
522 YYERROR;
523 }
524 }
Andreas Huberc9410c72016-07-28 12:18:40 -0700525 | interface_declarations method_declaration
526 {
Yifan Hong27e85db2016-11-09 15:45:52 -0800527 std::string errorMsg;
528 if ($2 != nullptr &&
529 !isValidInterfaceField($2->name().c_str(), &errorMsg)) {
530 std::cerr << "ERROR: " << errorMsg << " at "
531 << @2 << "\n";
532 YYERROR;
533 }
534
Yifan Hongbe627b32016-10-28 18:38:56 -0700535 if ($2 != nullptr) {
536 if (!ast->scope()->isInterface()) {
537 std::cerr << "ERROR: unknown error in interface declaration at "
538 << @2 << "\n";
539 YYERROR;
540 }
Steven Moreland14ee6742016-10-18 12:58:28 -0700541
Yifan Hongbe627b32016-10-28 18:38:56 -0700542 Interface *iface = static_cast<Interface *>(ast->scope());
543 if (!iface->addMethod($2)) {
544 std::cerr << "ERROR: Unable to add method '" << $2->name()
545 << "' at " << @2 << "\n";
546
547 YYERROR;
548 }
Steven Moreland14ee6742016-10-18 12:58:28 -0700549 }
Yifan Hongbe627b32016-10-28 18:38:56 -0700550 // ignore if $2 is nullptr (from error recovery)
Andreas Huberc9410c72016-07-28 12:18:40 -0700551 }
552 ;
553
554type_declarations
Andreas Hubera2723d22016-07-29 15:36:07 -0700555 : /* empty */
Yifan Hongbe627b32016-10-28 18:38:56 -0700556 | error_stmt
Andreas Huberc9410c72016-07-28 12:18:40 -0700557 | type_declarations type_declaration
558 ;
559
560type_declaration
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700561 : opt_annotations type_declaration_body
562 {
563 if ($2 != nullptr) {
564 $2->setAnnotations($1);
565 } else if (!$1->empty()) {
566 // Since typedefs are always resolved to their target it makes
567 // little sense to annotate them and have their annotations
568 // impose semantics other than their target type.
569 std::cerr << "ERROR: typedefs cannot be annotated. at " << @2
570 << "\n";
571
572 YYERROR;
573 }
Yifan Hong27e85db2016-11-09 15:45:52 -0800574 $$ = $2;
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700575 }
576 ;
577
578type_declaration_body
Yifan Hongbe627b32016-10-28 18:38:56 -0700579 : named_struct_or_union_declaration require_semicolon
580 | named_enum_declaration require_semicolon
581 | typedef_declaration require_semicolon
582 | interface_declaration require_semicolon
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700583 ;
584
585interface_declaration
Yifan Hong27e85db2016-11-09 15:45:52 -0800586 : INTERFACE valid_identifier opt_extends
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700587 {
588 if ($3 != NULL && !$3->isInterface()) {
Yifan Hongbe627b32016-10-28 18:38:56 -0700589 std::cerr << "ERROR: You can only extend interfaces. at " << @3
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700590 << "\n";
591
592 YYERROR;
593 }
594
595 if ($2[0] != 'I') {
596 std::cerr << "ERROR: All interface names must start with an 'I' "
597 << "prefix. at " << @2 << "\n";
598
599 YYERROR;
600 }
601
Yifan Honga4b53d02016-10-31 17:29:10 -0700602 Interface *iface = new Interface($2, convertYYLoc(@2), static_cast<Interface *>($3));
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700603
604 // Register interface immediately so it can be referenced inside
605 // definition.
606 std::string errorMsg;
607 if (!ast->addScopedType(iface, &errorMsg)) {
608 std::cerr << "ERROR: " << errorMsg << " at " << @2 << "\n";
609 YYERROR;
610 }
611
612 ast->enterScope(iface);
613 }
614 '{' interface_declarations '}'
615 {
Yifan Hongbe627b32016-10-28 18:38:56 -0700616 if (!ast->scope()->isInterface()) {
617 std::cerr << "ERROR: unknown error in interface declaration at "
618 << @5 << "\n";
619 YYERROR;
620 }
621
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700622 Interface *iface = static_cast<Interface *>(ast->scope());
623
624 ast->leaveScope();
625
626 $$ = iface;
627 }
Andreas Huberc9410c72016-07-28 12:18:40 -0700628 ;
629
630typedef_declaration
Yifan Hong27e85db2016-11-09 15:45:52 -0800631 : TYPEDEF type valid_identifier
Andreas Huberc9410c72016-07-28 12:18:40 -0700632 {
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700633 std::string errorMsg;
Yifan Honga4b53d02016-10-31 17:29:10 -0700634 if (!ast->addTypeDef($3, $2, convertYYLoc(@3), &errorMsg)) {
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700635 std::cerr << "ERROR: " << errorMsg << " at " << @3 << "\n";
Andreas Huber5a545442016-08-03 10:44:56 -0700636 YYERROR;
637 }
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700638
639 $$ = nullptr;
Andreas Huberc9410c72016-07-28 12:18:40 -0700640 }
641 ;
642
Yifan Hong52165692016-08-12 18:06:40 -0700643const_expr
Yifan Hongf24fa852016-09-23 11:03:15 -0700644 : INTEGER { $$ = new ConstantExpression($1); }
Yifan Hongb44a6c82016-09-22 15:50:18 -0700645 | fqname
646 {
Yifan Hongf24fa852016-09-23 11:03:15 -0700647 if(!$1->isValidValueName()) {
648 std::cerr << "ERROR: '" << $1->string()
649 << "' does not refer to an enum value at "
650 << @1 << ".\n";
651 YYERROR;
652 }
653 if($1->isIdentifier()) {
654 std::string identifier = $1->name();
655 LocalIdentifier *iden = ast->scope()->lookupIdentifier(identifier);
656 if(!iden) {
Yifan Hongbe627b32016-10-28 18:38:56 -0700657 std::cerr << "ERROR: identifier " << $1->string()
658 << " could not be found at " << @1 << ".\n";
Yifan Hongf24fa852016-09-23 11:03:15 -0700659 YYERROR;
660 }
661 if(!iden->isEnumValue()) {
Yifan Hongbe627b32016-10-28 18:38:56 -0700662 std::cerr << "ERROR: identifier " << $1->string()
663 << " is not an enum value at " << @1 << ".\n";
Yifan Hongf24fa852016-09-23 11:03:15 -0700664 YYERROR;
665 }
666 $$ = new ConstantExpression(
667 *(static_cast<EnumValue *>(iden)->constExpr()), $1->string());
668 } else {
669 std::string errorMsg;
670 EnumValue *v = ast->lookupEnumValue(*($1), &errorMsg);
671 if(v == nullptr) {
672 std::cerr << "ERROR: " << errorMsg << " at " << @1 << ".\n";
673 YYERROR;
674 }
675 $$ = new ConstantExpression(*(v->constExpr()), $1->string());
676 }
Yifan Hongb44a6c82016-09-22 15:50:18 -0700677 }
Yifan Hong52165692016-08-12 18:06:40 -0700678 | const_expr '?' const_expr ':' const_expr
679 {
Yifan Hongb44a6c82016-09-22 15:50:18 -0700680 $$ = new ConstantExpression($1, $3, $5);
Yifan Hong52165692016-08-12 18:06:40 -0700681 }
682 | const_expr LOGICAL_OR const_expr { $$ = new ConstantExpression($1, "||", $3); }
683 | const_expr LOGICAL_AND const_expr { $$ = new ConstantExpression($1, "&&", $3); }
684 | const_expr '|' const_expr { $$ = new ConstantExpression($1, "|" , $3); }
685 | const_expr '^' const_expr { $$ = new ConstantExpression($1, "^" , $3); }
686 | const_expr '&' const_expr { $$ = new ConstantExpression($1, "&" , $3); }
687 | const_expr EQUALITY const_expr { $$ = new ConstantExpression($1, "==", $3); }
688 | const_expr NEQ const_expr { $$ = new ConstantExpression($1, "!=", $3); }
689 | const_expr '<' const_expr { $$ = new ConstantExpression($1, "<" , $3); }
690 | const_expr '>' const_expr { $$ = new ConstantExpression($1, ">" , $3); }
691 | const_expr LEQ const_expr { $$ = new ConstantExpression($1, "<=", $3); }
692 | const_expr GEQ const_expr { $$ = new ConstantExpression($1, ">=", $3); }
693 | const_expr LSHIFT const_expr { $$ = new ConstantExpression($1, "<<", $3); }
694 | const_expr RSHIFT const_expr { $$ = new ConstantExpression($1, ">>", $3); }
695 | const_expr '+' const_expr { $$ = new ConstantExpression($1, "+" , $3); }
696 | const_expr '-' const_expr { $$ = new ConstantExpression($1, "-" , $3); }
697 | const_expr '*' const_expr { $$ = new ConstantExpression($1, "*" , $3); }
698 | const_expr '/' const_expr { $$ = new ConstantExpression($1, "/" , $3); }
699 | const_expr '%' const_expr { $$ = new ConstantExpression($1, "%" , $3); }
700 | '+' const_expr %prec UNARY_PLUS { $$ = new ConstantExpression("+", $2); }
701 | '-' const_expr %prec UNARY_MINUS { $$ = new ConstantExpression("-", $2); }
702 | '!' const_expr { $$ = new ConstantExpression("!", $2); }
703 | '~' const_expr { $$ = new ConstantExpression("~", $2); }
704 | '(' const_expr ')' { $$ = $2; }
Yifan Hongbe627b32016-10-28 18:38:56 -0700705 | '(' error ')'
706 {
707 ast->addSyntaxError();
708 // to avoid segfaults
709 $$ = new ConstantExpression(ConstantExpression::Zero(ScalarType::KIND_INT32));
710 }
Yifan Hong52165692016-08-12 18:06:40 -0700711 ;
712
Andreas Huberc9410c72016-07-28 12:18:40 -0700713method_declaration
Yifan Hongbe627b32016-10-28 18:38:56 -0700714 : error_stmt { $$ = nullptr; }
Yifan Hong27e85db2016-11-09 15:45:52 -0800715 | opt_annotations valid_identifier '(' typed_vars ')' require_semicolon
Andreas Huberc9410c72016-07-28 12:18:40 -0700716 {
Iliyan Malchev639bff82016-08-13 14:24:11 -0700717 $$ = new Method($2, $4, new std::vector<TypedVar *>, false, $1);
718 }
Yifan Hong27e85db2016-11-09 15:45:52 -0800719 | opt_annotations ONEWAY valid_identifier '(' typed_vars ')' require_semicolon
Iliyan Malchev639bff82016-08-13 14:24:11 -0700720 {
721 $$ = new Method($3, $5, new std::vector<TypedVar *>, true, $1);
Andreas Huberc9410c72016-07-28 12:18:40 -0700722 }
Yifan Hong27e85db2016-11-09 15:45:52 -0800723 | opt_annotations valid_identifier '(' typed_vars ')' GENERATES '(' typed_vars ')' require_semicolon
Andreas Huberc9410c72016-07-28 12:18:40 -0700724 {
Iliyan Malchev639bff82016-08-13 14:24:11 -0700725 $$ = new Method($2, $4, $8, false, $1);
Andreas Huberc9410c72016-07-28 12:18:40 -0700726 }
727 ;
728
729typed_vars
730 : /* empty */
731 {
Andreas Huber881227d2016-08-02 14:20:21 -0700732 $$ = new std::vector<TypedVar *>;
Andreas Huberc9410c72016-07-28 12:18:40 -0700733 }
734 | typed_var
735 {
Andreas Huber881227d2016-08-02 14:20:21 -0700736 $$ = new std::vector<TypedVar *>;
Andreas Huberc9410c72016-07-28 12:18:40 -0700737 $$->push_back($1);
738 }
739 | typed_vars ',' typed_var
740 {
741 $$ = $1;
742 $$->push_back($3);
743 }
744 ;
745
Yifan Hong27e85db2016-11-09 15:45:52 -0800746typed_var : type valid_identifier { $$ = new TypedVar($2, $1); }
Andreas Huberc9410c72016-07-28 12:18:40 -0700747 ;
748
749
750struct_or_union_keyword
751 : STRUCT { $$ = CompoundType::STYLE_STRUCT; }
752 | UNION { $$ = CompoundType::STYLE_UNION; }
753 ;
754
755named_struct_or_union_declaration
Yifan Hong27e85db2016-11-09 15:45:52 -0800756 : struct_or_union_keyword valid_identifier
Andreas Huberc9410c72016-07-28 12:18:40 -0700757 {
Yifan Honga4b53d02016-10-31 17:29:10 -0700758 CompoundType *container = new CompoundType($1, $2, convertYYLoc(@2));
Andreas Huberc9410c72016-07-28 12:18:40 -0700759 ast->enterScope(container);
760 }
761 struct_or_union_body
762 {
Yifan Hongbe627b32016-10-28 18:38:56 -0700763 if (!ast->scope()->isCompoundType()) {
764 std::cerr << "ERROR: unknown error in struct or union declaration at "
765 << @4 << "\n";
766 YYERROR;
767 }
Andreas Huberc9410c72016-07-28 12:18:40 -0700768 CompoundType *container = static_cast<CompoundType *>(ast->scope());
769
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700770 std::string errorMsg;
771 if (!container->setFields($4, &errorMsg)) {
772 std::cerr << "ERROR: " << errorMsg << " at " << @4 << "\n";
Andreas Huber5a545442016-08-03 10:44:56 -0700773 YYERROR;
774 }
775
Andreas Huberc9410c72016-07-28 12:18:40 -0700776 ast->leaveScope();
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700777
Andreas Huber9ed827c2016-08-22 12:31:13 -0700778 if (!ast->addScopedType(container, &errorMsg)) {
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700779 std::cerr << "ERROR: " << errorMsg << " at " << @2 << "\n";
Andreas Huber5a545442016-08-03 10:44:56 -0700780 YYERROR;
781 }
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700782
783 $$ = container;
Andreas Huberc9410c72016-07-28 12:18:40 -0700784 }
785 ;
786
Andreas Huberc9410c72016-07-28 12:18:40 -0700787struct_or_union_body
788 : '{' field_declarations '}' { $$ = $2; }
789 ;
790
791field_declarations
Andreas Huber881227d2016-08-02 14:20:21 -0700792 : /* empty */ { $$ = new std::vector<CompoundField *>; }
Andreas Huberc9410c72016-07-28 12:18:40 -0700793 | field_declarations field_declaration
794 {
795 $$ = $1;
796
797 if ($2 != NULL) {
798 $$->push_back($2);
799 }
800 }
801 ;
802
803field_declaration
Yifan Hongbe627b32016-10-28 18:38:56 -0700804 : error_stmt { $$ = nullptr; }
Yifan Hong27e85db2016-11-09 15:45:52 -0800805 | type valid_identifier require_semicolon
806 {
807 std::string errorMsg;
808 if (ast->scope()->isCompoundType() &&
809 static_cast<CompoundType *>(ast->scope())->style() == CompoundType::STYLE_STRUCT &&
810 !isValidStructField($2, &errorMsg)) {
811 std::cerr << "ERROR: " << errorMsg << " at "
812 << @2 << "\n";
813 YYERROR;
814 }
815 $$ = new CompoundField($2, $1);
816 }
817 | annotated_compound_declaration ';'
818 {
819 std::string errorMsg;
820 if (ast->scope()->isCompoundType() &&
821 static_cast<CompoundType *>(ast->scope())->style() == CompoundType::STYLE_STRUCT &&
822 $1 != nullptr &&
823 $1->isNamedType() &&
824 !isValidStructField(static_cast<NamedType *>($1)->localName().c_str(), &errorMsg)) {
825 std::cerr << "ERROR: " << errorMsg << " at "
826 << @2 << "\n";
827 YYERROR;
828 }
829 $$ = NULL;
830 }
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700831 ;
832
833annotated_compound_declaration
834 : opt_annotations compound_declaration
835 {
836 $2->setAnnotations($1);
837 $$ = $2;
838 }
839 ;
840
841compound_declaration
Yifan Honga2855012016-10-11 13:36:54 -0700842 : named_struct_or_union_declaration { $$ = $1; }
Yifan Hong6a2fedf2016-10-11 13:44:07 -0700843 | named_enum_declaration { $$ = $1; }
Andreas Huberc9410c72016-07-28 12:18:40 -0700844 ;
845
Steven Moreland1c71fd52016-11-29 14:03:33 -0800846enum_storage_type
847 : ':' fqtype
Andreas Huber8d3ac0c2016-08-04 14:49:23 -0700848 {
849 $$ = $2;
850
851 if ($$ != NULL && !$$->isValidEnumStorageType()) {
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700852 std::cerr << "ERROR: Invalid enum storage type specified. at "
853 << @2 << "\n";
854
Yifan Hongbe627b32016-10-28 18:38:56 -0700855 YYERROR;
Andreas Huber8d3ac0c2016-08-04 14:49:23 -0700856 }
857 }
Andreas Huberc9410c72016-07-28 12:18:40 -0700858 ;
859
860opt_comma
861 : /* empty */
862 | ','
863 ;
864
865named_enum_declaration
Steven Moreland1c71fd52016-11-29 14:03:33 -0800866 : ENUM valid_identifier enum_storage_type
Andreas Huberc9410c72016-07-28 12:18:40 -0700867 {
Yifan Honga4b53d02016-10-31 17:29:10 -0700868 ast->enterScope(new EnumType($2, convertYYLoc(@2), $3));
Yifan Hongf24fa852016-09-23 11:03:15 -0700869 }
870 enum_declaration_body
871 {
Yifan Hongbe627b32016-10-28 18:38:56 -0700872 if (!ast->scope()->isEnum()) {
873 std::cerr << "ERROR: unknown error in enum declaration at "
874 << @5 << "\n";
875 YYERROR;
876 }
877
Yifan Hongf24fa852016-09-23 11:03:15 -0700878 EnumType *enumType = static_cast<EnumType *>(ast->scope());
879 ast->leaveScope();
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700880
881 std::string errorMsg;
Andreas Huber9ed827c2016-08-22 12:31:13 -0700882 if (!ast->addScopedType(enumType, &errorMsg)) {
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700883 std::cerr << "ERROR: " << errorMsg << " at " << @2 << "\n";
Andreas Huber5a545442016-08-03 10:44:56 -0700884 YYERROR;
885 }
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700886
887 $$ = enumType;
Andreas Huberc9410c72016-07-28 12:18:40 -0700888 }
889 ;
890
Yifan Hongf24fa852016-09-23 11:03:15 -0700891enum_declaration_body
892 : '{' enum_values opt_comma '}' { $$ = $2; }
893 ;
894
Andreas Huberc9410c72016-07-28 12:18:40 -0700895enum_value
Yifan Hong27e85db2016-11-09 15:45:52 -0800896 : valid_identifier { $$ = new EnumValue($1); }
897 | valid_identifier '=' const_expr { $$ = new EnumValue($1, $3); }
Andreas Huberc9410c72016-07-28 12:18:40 -0700898 ;
899
900enum_values
901 : /* empty */
Yifan Hongf24fa852016-09-23 11:03:15 -0700902 { /* do nothing */ }
Andreas Huberc9410c72016-07-28 12:18:40 -0700903 | enum_value
904 {
Yifan Hongbe627b32016-10-28 18:38:56 -0700905 if (!ast->scope()->isEnum()) {
906 std::cerr << "ERROR: unknown error in enum declaration at "
907 << @1 << "\n";
908 YYERROR;
909 }
910
Yifan Hongf24fa852016-09-23 11:03:15 -0700911 static_cast<EnumType *>(ast->scope())->addValue($1);
Andreas Huberc9410c72016-07-28 12:18:40 -0700912 }
913 | enum_values ',' enum_value
914 {
Yifan Hongbe627b32016-10-28 18:38:56 -0700915 if (!ast->scope()->isEnum()) {
916 std::cerr << "ERROR: unknown error in enum declaration at "
917 << @3 << "\n";
918 YYERROR;
919 }
920
Yifan Hongf24fa852016-09-23 11:03:15 -0700921 static_cast<EnumType *>(ast->scope())->addValue($3);
Andreas Huberc9410c72016-07-28 12:18:40 -0700922 }
923 ;
924
Yifan Hongbd33e382016-11-02 13:30:17 -0700925array_type_base
Yifan Hongae16eed2016-09-23 13:25:25 -0700926 : fqtype { $$ = $1; }
Yifan Hongbf459bc2016-08-23 16:50:37 -0700927 | TEMPLATED '<' type '>'
Andreas Huberb95ea8a2016-08-15 15:35:42 -0700928 {
Andreas Huber86a112b2016-10-19 14:25:16 -0700929 if (!$1->isVector() && $3->isBinder()) {
Yifan Hongbf459bc2016-08-23 16:50:37 -0700930 std::cerr << "ERROR: TemplatedType of interface types are not "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700931 << "supported. at " << @3 << "\n";
Andreas Huber70a59e12016-08-16 12:57:01 -0700932
Andreas Huberb95ea8a2016-08-15 15:35:42 -0700933 YYERROR;
934 }
Yifan Hongbf459bc2016-08-23 16:50:37 -0700935 $1->setElementType($3);
936 $$ = $1;
937 }
938 | TEMPLATED '<' TEMPLATED '<' type RSHIFT
939 {
940 if ($5->isBinder()) {
941 std::cerr << "ERROR: TemplatedType of interface types are not "
942 << "supported. at " << @5 << "\n";
Andreas Huberb95ea8a2016-08-15 15:35:42 -0700943
Yifan Hongbf459bc2016-08-23 16:50:37 -0700944 YYERROR;
945 }
946 $3->setElementType($5);
947 $1->setElementType($3);
948 $$ = $1;
Andreas Huberb95ea8a2016-08-15 15:35:42 -0700949 }
Yifan Hongbd33e382016-11-02 13:30:17 -0700950 ;
951
952array_type
953 : array_type_base '[' const_expr ']'
954 {
955 if ($1->isBinder()) {
956 std::cerr << "ERROR: Arrays of interface types are not supported."
957 << " at " << @1 << "\n";
958
959 YYERROR;
960 }
961 if ($1->isArray()) {
962 $$ = new ArrayType(static_cast<ArrayType *>($1), $3);
963 } else {
964 $$ = new ArrayType($1, $3);
965 }
966 }
967 | array_type '[' const_expr ']'
968 {
969 $$ = $1;
970 $$->appendDimension($3);
971 }
972 ;
973
974type
975 : array_type_base { $$ = $1; }
976 | array_type { $$ = $1; }
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700977 | annotated_compound_declaration { $$ = $1; }
Andreas Huber295ad302016-08-16 11:35:00 -0700978 | INTERFACE { $$ = new GenericBinder; }
Andreas Huberc9410c72016-07-28 12:18:40 -0700979 ;
980
Andreas Huberc9410c72016-07-28 12:18:40 -0700981%%
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700982
983#include <android-base/logging.h>
984
985void yy::parser::error(
986 const yy::parser::location_type &where,
987 const std::string &errstr) {
988 std::cerr << "ERROR: " << errstr << " at " << where << "\n";
989}
990