Switch to 'glr' skeleton parser, better diagnostics through location tracking.

Change-Id: I34f510f3bf8d1e6da06de350456bd2804ca236db
Bug: 28679009
diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy
index ee2632c..55fee10 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -19,23 +19,22 @@
 
 using namespace android;
 
-extern int yylex(YYSTYPE *yylval_param, void *yyscanner);
-extern int column;
-
-int yyerror(AST *, const char *s) {
-    fflush(stdout);
-    printf("\n%*s\n%*s\n", column, "^", column, s);
-
-    return 0;
-}
+extern int yylex(yy::parser::semantic_type *, yy::parser::location_type *, void *);
 
 #define scanner ast->scanner()
 
 %}
 
+%initial-action {
+    // Initialize the initial location.
+    @$.begin.filename = @$.end.filename =
+        const_cast<std::string *>(&ast->getFilename());
+}
+
 %parse-param { android::AST *ast }
 %lex-param { void *scanner }
 %pure-parser
+%skeleton "glr.cc"
 
 %token<str> ENUM
 %token<str> EXTENDS
@@ -207,9 +206,10 @@
       {
           $$ = ast->lookupType($1);
           if ($$ == NULL) {
-              yyerror(ast,
-                      android::String8::format(
-                          "Failed to lookup type '%s'.", $1).string());
+              std::cerr << "ERROR: Failed to lookup type '" << $1 << "' at "
+                        << @1
+                        << "\n";
+
               YYERROR;
           }
       }
@@ -217,9 +217,9 @@
       {
           $$ = ast->lookupType($1);
           if ($$ == NULL) {
-              yyerror(ast,
-                      android::String8::format(
-                          "Failed to lookup type '%s'.", $1).string());
+              std::cerr << "Failed to lookup type '" << $1 << "' at " << @1
+                        << "\n";
+
               YYERROR;
           }
       }
@@ -230,7 +230,12 @@
     : PACKAGE FQNAME ';'
       {
           if (!ast->setPackage($2)) {
-              yyerror(ast, "Malformed package identifier.");
+              std::cerr << "ERROR: Malformed package identifier '"
+                        << $2
+                        << "' at "
+                        << @2
+                        << "\n";
+
               YYERROR;
           }
       }
@@ -240,9 +245,8 @@
     | imports IMPORT FQNAME ';'
       {
           if (!ast->addImport($3)) {
-              yyerror(ast,
-                      android::String8::format(
-                          "Unable to import '%s'.", $3));
+              std::cerr << "ERROR: Unable to import '" << $3 << "' at " << @3
+                        << "\n";
 
               YYERROR;
           }
@@ -250,9 +254,8 @@
     | imports IMPORT IDENTIFIER ';'
       {
           if (!ast->addImport($3)) {
-              yyerror(ast,
-                      android::String8::format(
-                          "Unable to import '%s'.", $3));
+              std::cerr << "ERROR: Unable to import '" << $3 << "' at " << @3
+                        << "\n";
 
               YYERROR;
           }
@@ -267,14 +270,15 @@
     : opt_annotations INTERFACE IDENTIFIER opt_extends
       {
           if ($4 != NULL && !$4->isInterface()) {
-              fprintf(stderr, "ERROR: You can only extend interfaces.\n");
+              std::cerr << "ERROR: You can only extend interfaces. at" << @4
+                        << "\n";
+
               YYERROR;
           }
 
           if ($3[0] != 'I') {
-              fprintf(stderr,
-                      "ERROR: All interface names must start with an 'I' "
-                      "prefix.\n");
+              std::cerr << "ERROR: All interface names must start with an 'I' "
+                        << "prefix. at " << @3 << "\n";
 
               YYERROR;
           }
@@ -283,7 +287,9 @@
 
           // Register interface immediately so it can be referenced inside
           // definition.
-          if (!ast->addScopedType($3, iface)) {
+          std::string errorMsg;
+          if (!ast->addScopedType($3, iface, &errorMsg)) {
+              std::cerr << "ERROR: " << errorMsg << " at " << @3 << "\n";
               YYERROR;
           }
 
@@ -323,7 +329,10 @@
     : TYPEDEF type IDENTIFIER
       {
           TypeDef *def = new TypeDef($2);
-          if (!ast->addScopedType($3, def)) {
+
+          std::string errorMsg;
+          if (!ast->addScopedType($3, def, &errorMsg)) {
+              std::cerr << "ERROR: " << errorMsg << " at " << @3 << "\n";
               YYERROR;
           }
       }
@@ -412,12 +421,16 @@
       {
           CompoundType *container = static_cast<CompoundType *>(ast->scope());
 
-          if (!container->setFields($4)) {
+          std::string errorMsg;
+          if (!container->setFields($4, &errorMsg)) {
+              std::cerr << "ERROR: " << errorMsg << " at " << @4 << "\n";
               YYERROR;
           }
 
           ast->leaveScope();
-          if (!ast->addScopedType($2, container)) {
+
+          if (!ast->addScopedType($2, container, &errorMsg)) {
+              std::cerr << "ERROR: " << errorMsg << " at " << @2 << "\n";
               YYERROR;
           }
       }
@@ -433,12 +446,16 @@
       {
           CompoundType *container = static_cast<CompoundType *>(ast->scope());
 
-          if (!container->setFields($4)) {
+          std::string errorMsg;
+          if (!container->setFields($4, &errorMsg)) {
+              std::cerr << "ERROR: " << errorMsg << " at " << @4 << "\n";
               YYERROR;
           }
 
           ast->leaveScope();
-          if (!ast->addScopedType($2, container)) {
+
+          if (!ast->addScopedType($2, container, &errorMsg)) {
+              std::cerr << "ERROR: " << errorMsg << " at " << @2 << "\n";
               YYERROR;
           }
 
@@ -475,7 +492,9 @@
           $$ = $2;
 
           if ($$ != NULL && !$$->isValidEnumStorageType()) {
-              fprintf(stderr, "ERROR: Invalid enum storage type specified.\n");
+              std::cerr << "ERROR: Invalid enum storage type specified. at "
+                        << @2 << "\n";
+
               YYABORT;
           }
       }
@@ -490,7 +509,10 @@
     : ENUM IDENTIFIER opt_storage_type '{' enum_values opt_comma '}'
       {
           EnumType *enumType = new EnumType($5, $3);
-          if (!ast->addScopedType($2, enumType)) {
+
+          std::string errorMsg;
+          if (!ast->addScopedType($2, enumType, &errorMsg)) {
+              std::cerr << "ERROR: " << errorMsg << " at " << @2 << "\n";
               YYERROR;
           }
       }
@@ -500,7 +522,11 @@
     : ENUM '{' enum_values opt_comma '}'
       {
           EnumType *enumType = new EnumType($3);
-          if (!ast->addScopedType(NULL /* localName */, enumType)) {
+
+          std::string errorMsg;
+          if (!ast->addScopedType(NULL /* localName */, enumType, &errorMsg)) {
+              // This should never fail.
+              std::cerr << "ERROR: " << errorMsg << "\n";
               YYERROR;
           }
 
@@ -509,7 +535,10 @@
     | ENUM IDENTIFIER opt_storage_type '{' enum_values opt_comma '}'
       {
           EnumType *enumType = new EnumType($5, $3);
-          if (!ast->addScopedType($2, enumType)) {
+
+          std::string errorMsg;
+          if (!ast->addScopedType($2, enumType, &errorMsg)) {
+              std::cerr << "ERROR: " << errorMsg << " at " << @2 << "\n";
               YYERROR;
           }
 
@@ -544,8 +573,8 @@
     | fqname '[' INTEGER ']'
       {
           if ($1->isBinder()) {
-              fprintf(stderr,
-                      "ERROR: Arrays of interface types are not supported.");
+              std::cerr << "ERROR: Arrays of interface types are not supported."
+                        << " at " << @1 << "\n";
 
               YYERROR;
           }
@@ -555,8 +584,8 @@
     | VEC '<' fqname '>'
       {
           if ($3->isBinder()) {
-              fprintf(stderr,
-                      "ERROR: Vectors of interface types are not supported.");
+              std::cerr << "ERROR: Vectors of interface types are not "
+                        << "supported. at " << @3 << "\n";
 
               YYERROR;
           }
@@ -574,3 +603,12 @@
     ;
 
 %%
+
+#include <android-base/logging.h>
+
+void yy::parser::error(
+        const yy::parser::location_type &where,
+        const std::string &errstr) {
+    std::cerr << "ERROR: " << errstr << " at " << where << "\n";
+}
+