From 8690833dd7d8448e27f11addf03ec4f296963ee1 Mon Sep 17 00:00:00 2001
From: Abhishek Pandit-Subedi <abhishekpandit@chromium.org>
Date: Mon, 15 Mar 2021 13:44:51 -0700
Subject: [PATCH] Use local rules for flex/bison

Use local flex and bison rules for the packet parser instead of
depending on the rules in common-mk. Right now, the packet parser is
using a re-entrant parser which can't be used with C++ codegen for flex.
Common-mk maintainers would like the flex code to use C++ codegen since
it is compiling the file as C++.

Bug: 176847216
Tag: #floss
Test: atest --host bluetooth_test_gd
Change-Id: I731adcff7c966543300d2cdf1f87ef2a69b8a211
---
 system/gd/packet/parser/BUILD.gn  |  4 +-
 system/gd/packet/parser/bison.gni | 75 +++++++++++++++++++++++++++++++
 system/gd/packet/parser/flex.gni  | 70 +++++++++++++++++++++++++++++
 3 files changed, 147 insertions(+), 2 deletions(-)
 create mode 100644 system/gd/packet/parser/bison.gni
 create mode 100644 system/gd/packet/parser/flex.gni

diff --git a/system/gd/packet/parser/BUILD.gn b/system/gd/packet/parser/BUILD.gn
index 9889672cc83..dd4f3b09710 100644
--- a/system/gd/packet/parser/BUILD.gn
+++ b/system/gd/packet/parser/BUILD.gn
@@ -14,8 +14,8 @@
 #  limitations under the License.
 #
 
-import("//common-mk/bison.gni")
-import("//common-mk/flex.gni")
+import("flex.gni")
+import("bison.gni")
 
 config("pktgen_configs") {
   include_dirs = [ "//bt/gd/packet/parser" ]
diff --git a/system/gd/packet/parser/bison.gni b/system/gd/packet/parser/bison.gni
new file mode 100644
index 00000000000..b52541b32f3
--- /dev/null
+++ b/system/gd/packet/parser/bison.gni
@@ -0,0 +1,75 @@
+#
+#  Copyright 2021 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+# Bison is a parser generator which reads a specification of a context-free
+# language and generates a parser which decides whether the input conforms to
+# the grammar specified.
+
+# Generate header and source files using Bison.
+#
+# Note: We generate C++ output for Bison. We also set --language to C++
+# (equivalent to %language c++) which forces Bison to generate a C++ parser.
+#
+# Parameters:
+#   sources: Grammar files used to generate the parsers.
+template("bison_source") {
+  action_name = "${target_name}_gen"
+  action_foreach(action_name) {
+    forward_variables_from(invoker, [ "sources" ])
+    assert(defined(sources), "sources must be set")
+    foreach(s, sources) {
+      assert(get_path_info(s, "extension") == "yy",
+             "Expecting Bison extension yy: ${s}")
+    }
+
+    script = "//common-mk/file_generator_wrapper.py"
+    outprefix = "${target_gen_dir}/{{source_name_part}}"
+    args = [
+      "bison",
+      "--language=c++",
+      "--defines=${outprefix}.h",
+      "-o",
+      "${outprefix}.cc",
+      "{{source}}",
+    ]
+    outputs = [
+      "${outprefix}.h",
+      "${outprefix}.cc",
+    ]
+  }
+
+  all_dependent_config_name = "_${target_name}_all_dependent_config"
+  config(all_dependent_config_name) {
+    include_dirs = [ "${target_gen_dir}" ]
+  }
+
+  source_set(target_name) {
+    sources = get_target_outputs(":${action_name}")
+    all_dependent_configs = [ ":${all_dependent_config_name}" ]
+    deps = [ ":${action_name}" ]
+
+    if (defined(invoker.configs)) {
+      configs += invoker.configs
+    }
+
+    # Silence some warnings. The autogenerated code includes parts that have
+    # fallthroughs and unreachable code. This may silence legitimate issues in
+    # user written code in the grammar files as well. User beware!
+    cflags_cc = [
+      "-Wno-implicit-fallthrough",
+      "-Wno-unreachable-code",
+    ]
+  }
+}
diff --git a/system/gd/packet/parser/flex.gni b/system/gd/packet/parser/flex.gni
new file mode 100644
index 00000000000..1fcba233d4e
--- /dev/null
+++ b/system/gd/packet/parser/flex.gni
@@ -0,0 +1,70 @@
+#
+#  Copyright 2021 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+# Flex (fast lexical analyzer generator) is used for parsing languages. It is
+# commonly used with a parser generator (like Bison).
+
+# Generate source files using Flex.
+#
+# Note: We generate .cc files for Flex. However, you must set %option c++ if you
+# want to generate a C++ scanner class. We don't use --c++ in case you have
+# %option reentrant set, which is mutually exclusive with %option c++.
+#
+# Parameters:
+#   sources: Files used to generate the lexers.
+template("flex_source") {
+  action_name = "${target_name}_gen"
+  action_foreach(action_name) {
+    forward_variables_from(invoker, [ "sources" ])
+    assert(defined(sources), "sources must be set")
+    foreach(s, sources) {
+      assert(get_path_info(s, "extension") == "ll",
+             "Expecting Flex extension ll: ${s}")
+    }
+
+    script = "//common-mk/file_generator_wrapper.py"
+    outformat = "${target_gen_dir}/{{source_name_part}}.cc"
+    args = [
+      "flex",
+      "-o",
+      outformat,
+      "{{source}}",
+    ]
+    outputs = [ outformat ]
+  }
+
+  all_dependent_config_name = "_${target_name}_all_dependent_config"
+  config(all_dependent_config_name) {
+    include_dirs = [ "${target_gen_dir}" ]
+  }
+
+  source_set(target_name) {
+    sources = get_target_outputs(":${action_name}")
+    all_dependent_configs = [ ":${all_dependent_config_name}" ]
+    deps = [ ":${action_name}" ]
+
+    if (defined(invoker.configs)) {
+      configs += invoker.configs
+    }
+
+    # Silence some warnings. The autogenerated code includes parts that have
+    # fallthroughs and unreachable code. This may silence legitimate issues in
+    # user written code in the lexer as well. User beware!
+    cflags_cc = [
+      "-Wno-implicit-fallthrough",
+      "-Wno-unreachable-code",
+    ]
+  }
+}
-- 
GitLab