Fixes issue where the correct file name was not printed out for semantic
errors or warnings when processing .bin_fmt and .isa files.

PiperOrigin-RevId: 672683580
Change-Id: Ibc517639e7001cf23e2c0266f0b994dcad047b47
diff --git a/mpact/sim/decoder/bin_format_visitor.cc b/mpact/sim/decoder/bin_format_visitor.cc
index 605b0f5..ff1fdda 100644
--- a/mpact/sim/decoder/bin_format_visitor.cc
+++ b/mpact/sim/decoder/bin_format_visitor.cc
@@ -21,6 +21,7 @@
 #include <istream>
 #include <list>
 #include <memory>
+#include <new>
 #include <string>
 #include <utility>
 #include <vector>
@@ -129,6 +130,7 @@
   // Create and add the error listener.
   set_error_listener(std::make_unique<decoder::DecoderErrorListener>());
   error_listener_->set_file_name(file_names[0]);
+  file_names_.push_back(file_names[0]);
   parser_wrapper.parser()->removeErrorListeners();
   parser_wrapper.parser()->addErrorListener(error_listener());
 
@@ -365,7 +367,7 @@
     for (auto iter = reference_map.lower_bound(format->name());
          iter != reference_map.upper_bound(format->name()); iter++) {
       std::string parent_format_name = iter->second;
-      VisitFormatDef(format_decl_map_[parent_format_name],
+      VisitFormatDef(format_decl_map_.at(parent_format_name),
                      bin_encoding_info.get());
       format_list.push_back(bin_encoding_info->GetFormat(parent_format_name));
     }
@@ -378,9 +380,11 @@
   std::vector<IncludeFileCtx *> include_files;
 
   for (auto *declaration : ctx->declaration()) {
+    context_file_map_.insert({declaration, current_file_index_});
     // Create map from format name to format ctx.
     if (declaration->format_def() != nullptr) {
       auto format_def = declaration->format_def();
+      context_file_map_.insert({format_def, current_file_index_});
       auto name = format_def->name->getText();
       auto iter = format_decl_map_.find(name);
       if (iter != format_decl_map_.end()) {
@@ -396,6 +400,7 @@
     // Create map from instruction group name to instruction group ctx.
     if (declaration->instruction_group_def() != nullptr) {
       auto group_def = declaration->instruction_group_def();
+      context_file_map_.insert({group_def, current_file_index_});
       auto name = group_def->name->getText();
       auto iter = group_decl_map_.find(name);
       if (iter != group_decl_map_.end()) {
@@ -414,6 +419,7 @@
   }
   // Create map from decoder name to decoder ctx.
   for (auto *decoder_def : ctx->decoder_def()) {
+    context_file_map_.insert({decoder_def, current_file_index_});
     auto name = decoder_def->name->getText();
     auto iter = decoder_decl_map_.find(name);
     if (iter != decoder_decl_map_.end()) {
@@ -470,7 +476,10 @@
     }
   }
   std::string previous_file_name = error_listener()->file_name();
+  int previous_file_index_ = current_file_index_;
   error_listener()->set_file_name(file_name);
+  file_names_.push_back(file_name);
+  current_file_index_ = file_names_.size() - 1;
   auto *include_parser = new BinFmtAntlrParserWrapper(&include_file);
   // We need to save the parser state so it's available for analysis after
   // we are done with building the parse trees.
@@ -482,13 +491,16 @@
   DeclarationListCtx *declaration_list =
       include_parser->parser()->top_level()->declaration_list();
   include_file.close();
-  error_listener()->set_file_name(previous_file_name);
   if (error_listener()->syntax_error_count() > 0) {
+    error_listener()->set_file_name(previous_file_name);
+    current_file_index_ = previous_file_index_;
     return;
   }
   include_file_stack_.push_back(file_name);
   PreProcessDeclarations(declaration_list);
   include_file_stack_.pop_back();
+  error_listener()->set_file_name(previous_file_name);
+  current_file_index_ = previous_file_index_;
 }
 
 void BinFormatVisitor::VisitFormatDef(FormatDefCtx *ctx,
@@ -505,7 +517,7 @@
     // Must specify either a width or it must inherit from a format that has
     // a width.
     error_listener_->semanticError(
-        ctx->start,
+        file_names_[context_file_map_.at(ctx)], ctx->start,
         absl::StrCat("Format '", format_name,
                      "': must specify a width or inherited format"));
     return;
@@ -523,13 +535,14 @@
     }
     if (parent_format == nullptr) {
       error_listener_->semanticError(
-          ctx->inherits_from()->start,
+          file_names_[context_file_map_.at(ctx)], ctx->inherits_from()->start,
           absl::StrCat("Parent format '", parent_name, "' not defined"));
       return;
     } else {
       int parent_width = parent_format->declared_width();
       if ((format_width != -1) && (format_width != parent_width)) {
         error_listener_->semanticError(
+            file_names_[context_file_map_.at(format_decl_map_.at(parent_name))],
             ctx->inherits_from()->start,
             absl::StrCat("Format '", format_name, "' declared width (",
                          format_width, ") differs from width inherited from '",
@@ -544,21 +557,26 @@
     format_res = encoding_info->AddFormat(format_name, format_width);
   }
   if (!format_res.ok()) {
-    error_listener_->semanticError(ctx->start, format_res.status().message());
+    error_listener_->semanticError(file_names_[context_file_map_.at(ctx)],
+                                   ctx->start, format_res.status().message());
     return;
   }
   // Parse the fields in the format.
   auto format = format_res.value();
+  auto file_index = context_file_map_.at(ctx);
   for (auto field : ctx->format_field_defs()->field_def()) {
+    context_file_map_.insert({field, file_index});
     VisitFieldDef(field, format, encoding_info);
   }
   // Parse the overlays in the format.
   for (auto overlay : ctx->format_field_defs()->overlay_def()) {
+    context_file_map_.insert({overlay, file_index});
     VisitOverlayDef(overlay, format);
   }
   auto status = format->ComputeAndCheckFormatWidth();
   if (!status.ok()) {
-    error_listener_->semanticError(ctx->start, status.message());
+    error_listener_->semanticError(file_names_[context_file_map_.at(ctx)],
+                                   ctx->start, status.message());
   }
 }
 
@@ -573,7 +591,8 @@
     int width = ConvertToInt(ctx->index()->number());
     auto status = format->AddField(field_name, is_signed, width);
     if (!status.ok()) {
-      error_listener_->semanticError(ctx->field_name, status.message());
+      error_listener_->semanticError(file_names_[context_file_map_.at(ctx)],
+                                     ctx->field_name, status.message());
     }
     return;
   }
@@ -607,25 +626,29 @@
   // For now, only support overlays <= 64 bit wide.
   if (width > 64) {
     error_listener_->semanticError(
-        ctx->width->number()->start,
+        file_names_[context_file_map_.at(ctx)], ctx->width->number()->start,
         "Only overlays <= 64 bits are supported for now");
     return;
   }
   // Visit the bitfield spec items.
   auto overlay_res = format->AddFieldOverlay(name, is_signed, width);
   if (!overlay_res.ok()) {
-    error_listener_->semanticError(ctx->start, overlay_res.status().message());
+    error_listener_->semanticError(file_names_[context_file_map_.at(ctx)],
+                                   ctx->start, overlay_res.status().message());
     return;
   }
   auto *overlay = overlay_res.value();
+  int file_index = context_file_map_.at(ctx);
   for (auto *bit_field : ctx->bit_field_list()->bit_field_spec()) {
+    context_file_map_.insert({bit_field, file_index});
     VisitOverlayBitField(bit_field, overlay);
   }
   if (overlay->computed_width() != overlay->declared_width()) {
     error_listener_->semanticError(
-        ctx->start, absl::StrCat("Declared width (", overlay->declared_width(),
-                                 ") differs from computed width (",
-                                 overlay->computed_width(), ")"));
+        file_names_[context_file_map_.at(ctx)], ctx->start,
+        absl::StrCat("Declared width (", overlay->declared_width(),
+                     ") differs from computed width (",
+                     overlay->computed_width(), ")"));
   }
 }
 
@@ -643,13 +666,15 @@
       auto status = overlay->AddFieldReference(ctx->IDENT()->getText(),
                                                std::move(bit_ranges_));
       if (!status.ok()) {
-        error_listener_->semanticError(ctx->start, status.message());
+        error_listener_->semanticError(file_names_[context_file_map_.at(ctx)],
+                                       ctx->start, status.message());
       }
       return;
     }
     auto status = overlay->AddFieldReference(ctx->IDENT()->getText());
     if (!status.ok()) {
-      error_listener_->semanticError(ctx->start, status.message());
+      error_listener_->semanticError(file_names_[context_file_map_.at(ctx)],
+                                     ctx->start, status.message());
     }
     return;
   }
@@ -661,7 +686,8 @@
     }
     auto status = overlay->AddFormatReference(std::move(bit_ranges_));
     if (!status.ok()) {
-      error_listener_->semanticError(ctx->start, status.message());
+      error_listener_->semanticError(file_names_[context_file_map_.at(ctx)],
+                                     ctx->start, status.message());
     }
     return;
   }
@@ -680,14 +706,15 @@
   auto format_iter = format_decl_map_.find(group_name);
   if (format_iter != format_decl_map_.end()) {
     error_listener_->semanticError(
-        ctx->start, absl::StrCat(group_name, ": illegal use of format name"));
+        file_names_[context_file_map_.at(ctx)], ctx->start,
+        absl::StrCat(group_name, ": illegal use of format name"));
   }
   int width = ConvertToInt(ctx->number());
   std::string format_name = ctx->format->getText();
   auto iter = format_decl_map_.find(format_name);
   if (iter == format_decl_map_.end()) {
     error_listener_->semanticError(
-        ctx->start,
+        file_names_[context_file_map_.at(ctx)], ctx->start,
         absl::StrCat("Undefined format '", format_name,
                      "' used by instruction group '", group_name, "'"));
     return nullptr;
@@ -697,6 +724,7 @@
     // Verify that the format width = declared width and also <= 64 bits wide.
     if (format->declared_width() != width) {
       error_listener_->semanticError(
+          file_names_[context_file_map_.at(format_decl_map_.at(format_name))],
           ctx->start,
           absl::StrCat("Width of format '", format_name, "' (",
                        format->declared_width(),
@@ -706,20 +734,25 @@
     }
     if (format->declared_width() > 64) {
       error_listener_->semanticError(
-          ctx->start, absl::StrCat("Instruction group '", group_name,
-                                   "': width must be <= 64 bits"));
+          file_names_[context_file_map_.at(format_decl_map_.at(format_name))],
+          ctx->start,
+          absl::StrCat("Instruction group '", group_name,
+                       "': width must be <= 64 bits"));
     }
   }
   auto inst_group_res =
       encoding_info->AddInstructionGroup(group_name, width, format_name);
   if (!inst_group_res.ok()) {
-    error_listener_->semanticError(ctx->start,
+    error_listener_->semanticError(file_names_[context_file_map_.at(ctx)],
+                                   ctx->start,
                                    inst_group_res.status().message());
     return nullptr;
   }
   // Parse the instruction encoding definitions in the instruction group.
   auto *inst_group = inst_group_res.value();
+  int file_index = context_file_map_.at(ctx);
   for (auto *inst_def : ctx->instruction_def_list()->instruction_def()) {
+    context_file_map_.insert({inst_def, file_index});
     VisitInstructionDef(inst_def, inst_group);
   }
   return inst_group_res.value();
@@ -741,7 +774,7 @@
     auto iter = format_decl_map_.find(format_name);
     if (iter == format_decl_map_.end()) {
       error_listener_->semanticError(
-          ctx->start,
+          file_names_[context_file_map_.at(ctx)], ctx->start,
           absl::StrCat("Format '", format_name, "' referenced by instruction '",
                        name, "' not defined"));
     } else {
@@ -752,7 +785,7 @@
   if ((format != nullptr) &&
       (format->declared_width() != inst_group->width())) {
     error_listener_->semanticError(
-        ctx->start,
+        file_names_[context_file_map_.at(ctx)], ctx->start,
         absl::StrCat(
             "Length of format '", format_name, "' (", format->declared_width(),
             ") differs from the declared width of the instruction group (",
@@ -762,7 +795,9 @@
       inst_group->AddInstructionEncoding(ctx->format_name, name, format);
   if (format == nullptr) return;
   // Add constraints to the instruction encoding.
+  int file_index = context_file_map_.at(ctx);
   for (auto *constraint : ctx->field_constraint_list()->field_constraint()) {
+    context_file_map_.insert({constraint, file_index});
     VisitConstraint(format, constraint, inst_encoding);
   }
 }
@@ -776,6 +811,7 @@
   // value or a structured binding assignment. If it's a binding assignment we
   // need to make sure each tuple has the same number of values as there are
   // idents to assign them to.
+  int file_index = context_file_map_.at(ctx);
   for (auto *assign_ctx : ctx->range_assignment()) {
     auto *range_info = new RangeAssignmentInfo();
     range_info_vec.push_back(range_info);
@@ -783,7 +819,7 @@
       std::string name = ident_ctx->getText();
       if (range_variable_names.contains(name)) {
         error_listener()->semanticError(
-            assign_ctx->start,
+            file_names_[file_index], assign_ctx->start,
             absl::StrCat("Duplicate binding variable name '", name, "'"));
         continue;
       }
@@ -796,7 +832,7 @@
       if (!RE2::PartialMatch(ctx->generator_instruction_def_list()->getText(),
                              range_info->range_regexes.back())) {
         error_listener()->semanticWarning(
-            assign_ctx->start,
+            file_names_[file_index], assign_ctx->start,
             absl::StrCat("Unreferenced binding variable '", name, "'."));
       }
     }
@@ -824,7 +860,7 @@
         // Clean up.
         for (auto *info : range_info_vec) delete info;
         error_listener_->semanticError(
-            assign_ctx->start,
+            file_names_[file_index], assign_ctx->start,
             "Number of values differs from number of identifiers");
         return;
       }
@@ -856,7 +892,7 @@
     auto ident = input_text.substr(start_pos, end_pos - start_pos);
     if (!range_variable_names.contains(ident)) {
       error_listener()->semanticError(
-          ctx->generator_instruction_def_list()->start,
+          file_names_[file_index], ctx->generator_instruction_def_list()->start,
           absl::StrCat("Undefined binding variable '", ident, "'"));
     }
     start_pos = end_pos;
@@ -880,6 +916,7 @@
       parser->parser()->instruction_def_list()->instruction_def();
   // Process the opcode spec.
   for (auto *inst_def : instruction_defs) {
+    context_file_map_.insert({inst_def, file_index});
     VisitInstructionDef(inst_def, inst_group);
   }
   // Clean up.
@@ -938,14 +975,14 @@
     if (field != nullptr) {
       if (field->width != length) {
         error_listener_->semanticWarning(
-            ctx->start,
+            file_names_[context_file_map_.at(ctx)], ctx->start,
             absl::StrCat("Field '", field_name, "' has width ", field->width,
                          " but constraint value is ", length, " bits"));
       }
     } else if (overlay != nullptr) {
       if (overlay->computed_width() != length) {
         error_listener_->semanticWarning(
-            ctx->start,
+            file_names_[context_file_map_.at(ctx)], ctx->start,
             absl::StrCat("Overlay '", field_name, "' has width ",
                          overlay->computed_width(), " but constraint value is ",
                          length, " bits"));
@@ -973,7 +1010,8 @@
                                                value);
   }
   if (!status.ok()) {
-    error_listener_->semanticError(ctx->start, status.message());
+    error_listener_->semanticError(file_names_[context_file_map_.at(ctx)],
+                                   ctx->start, status.message());
   }
 }
 
@@ -992,12 +1030,14 @@
       opcode_enum =
           opcode_enum_literal.substr(1, opcode_enum_literal.size() - 2);
       if (opcode_enum.empty()) {
-        error_listener_->semanticError(attr_ctx->start,
-                                       "Empty opcode enum string");
+        file_names_[context_file_map_.at(ctx)],
+            error_listener_->semanticError(attr_ctx->start,
+                                           "Empty opcode enum string");
       }
       if (opcode_count > 0) {
-        error_listener_->semanticError(attr_ctx->start,
-                                       "More than one opcode enum declaration");
+        file_names_[context_file_map_.at(ctx)],
+            error_listener_->semanticError(
+                attr_ctx->start, "More than one opcode enum declaration");
       }
       opcode_count++;
     }
@@ -1024,8 +1064,9 @@
         decoder->namespaces().push_back(namespace_name->getText());
       }
       if (namespace_count > 0) {
-        error_listener_->semanticError(attr_ctx->start,
-                                       "More than one namespace declaration");
+        file_names_[context_file_map_.at(ctx)],
+            error_listener_->semanticError(
+                attr_ctx->start, "More than one namespace declaration");
       }
       namespace_count++;
       continue;
@@ -1045,19 +1086,20 @@
       } else {
         auto iter = group_decl_map_.find(group_name);
         if (iter != group_decl_map_.end()) {
+          context_file_map_.insert({iter->second, current_file_index_});
           inst_group =
               VisitInstructionGroupDef(iter->second, encoding_info.get());
         }
         if (inst_group == nullptr) {
           error_listener_->semanticError(
-              attr_ctx->start,
+              file_names_[context_file_map_.at(ctx)], attr_ctx->start,
               absl::StrCat("No such instruction group: '", group_name, "'"));
           continue;
         }
       }
       if (group_name_set.contains(group_name)) {
         error_listener_->semanticError(
-            attr_ctx->start,
+            file_names_[context_file_map_.at(ctx)], attr_ctx->start,
             absl::StrCat("Instruction group '", group_name, "' listed twice"));
         continue;
       }
@@ -1073,8 +1115,9 @@
       std::string group_name = attr_ctx->group_name()->IDENT()->getText();
       if (group_name_set.contains(group_name)) {
         error_listener_->semanticError(
-            attr_ctx->start, absl::StrCat("Instruction group '", group_name,
-                                          "' listed twice - ignored"));
+            file_names_[context_file_map_.at(ctx)], attr_ctx->start,
+            absl::StrCat("Instruction group '", group_name,
+                         "' listed twice - ignored"));
         continue;
       }
       std::vector<InstructionGroup *> child_groups;
@@ -1084,8 +1127,9 @@
         auto child_name = ident->getText();
         if (group_name_set.contains(child_name)) {
           error_listener_->semanticError(
-              attr_ctx->start, absl::StrCat("Instruction group listed twice: '",
-                                            child_name, "' - ignored"));
+              file_names_[context_file_map_.at(ctx)], attr_ctx->start,
+              absl::StrCat("Instruction group listed twice: '", child_name,
+                           "' - ignored"));
           continue;
         }
         InstructionGroup *child_group = nullptr;
@@ -1101,8 +1145,9 @@
           }
           if (exists) {
             error_listener_->semanticError(
-                attr_ctx->start, absl::StrCat("Instruction group '", child_name,
-                                              "' listed twice"));
+                file_names_[context_file_map_.at(ctx)], attr_ctx->start,
+                absl::StrCat("Instruction group '", child_name,
+                             "' listed twice"));
             continue;
           }
         } else {
@@ -1115,7 +1160,7 @@
           }
           if (child_group == nullptr) {
             error_listener_->semanticError(
-                attr_ctx->start,
+                file_names_[context_file_map_.at(ctx)], attr_ctx->start,
                 absl::StrCat("Instruction group '", child_name, "' not found"));
             continue;
           }
@@ -1126,7 +1171,7 @@
         // Check that the child groups all use the same instruction format.
         if (group_format_name != child_group->format_name()) {
           error_listener_->semanticError(
-              attr_ctx->start,
+              file_names_[context_file_map_.at(ctx)], attr_ctx->start,
               absl::StrCat("Instruction group '", child_name,
                            "' must use format '", group_format_name,
                            ", to be merged into group '", group_name, "'"));
diff --git a/mpact/sim/decoder/bin_format_visitor.h b/mpact/sim/decoder/bin_format_visitor.h
index 68ac713..25a99bb 100644
--- a/mpact/sim/decoder/bin_format_visitor.h
+++ b/mpact/sim/decoder/bin_format_visitor.h
@@ -136,6 +136,11 @@
     error_listener_ = std::move(listener);
   }
 
+  int current_file_index_ = 0;
+  // Vector of file names.
+  std::vector<std::string> file_names_;
+  // Map from context pointer to file index.
+  absl::flat_hash_map<const antlr4::ParserRuleContext *, int> context_file_map_;
   // This stores a vector of include file root directories.
   std::vector<std::string> include_dir_vec_;
   // Keep track of files that are included in case there is recursive includes.
diff --git a/mpact/sim/decoder/decoder_error_listener.cc b/mpact/sim/decoder/decoder_error_listener.cc
index 3f2e17e..10335b3 100644
--- a/mpact/sim/decoder/decoder_error_listener.cc
+++ b/mpact/sim/decoder/decoder_error_listener.cc
@@ -29,10 +29,21 @@
 // Error listener methods.
 void DecoderErrorListener::semanticError(antlr4::Token *token,
                                          absl::string_view msg) {
+  semanticError(file_name_, token, msg);
+}
+
+void DecoderErrorListener::semanticWarning(antlr4::Token *token,
+                                           absl::string_view msg) {
+  semanticWarning(file_name_, token, msg);
+}
+
+void DecoderErrorListener::semanticError(const std::string &file_name,
+                                         antlr4::Token *token,
+                                         absl::string_view msg) {
   if (token != nullptr) {
     size_t line = token->getLine();
     size_t charPositionInLine = token->getCharPositionInLine();
-    LOG(ERROR) << absl::StrCat(file_name_, ":", line, ":", charPositionInLine,
+    LOG(ERROR) << absl::StrCat(file_name, ":", line, ":", charPositionInLine,
                                "  Error: ", msg, "\n");
   } else {
     LOG(ERROR) << absl::StrCat("Error: ", msg, "\n");
@@ -40,12 +51,13 @@
   semantic_error_count_++;
 }
 
-void DecoderErrorListener::semanticWarning(antlr4::Token *token,
+void DecoderErrorListener::semanticWarning(const std::string &file_name,
+                                           antlr4::Token *token,
                                            absl::string_view msg) {
   if (token != nullptr) {
     size_t line = token->getLine();
     size_t charPositionInLine = token->getCharPositionInLine();
-    LOG(WARNING) << absl::StrCat(file_name_, ":", line, ":", charPositionInLine,
+    LOG(WARNING) << absl::StrCat(file_name, ":", line, ":", charPositionInLine,
                                  "  Warning: ", msg, "\n");
   } else {
     LOG(WARNING) << absl::StrCat("Warning: ", msg, "\n");
diff --git a/mpact/sim/decoder/decoder_error_listener.h b/mpact/sim/decoder/decoder_error_listener.h
index e981529..77eb3d8 100644
--- a/mpact/sim/decoder/decoder_error_listener.h
+++ b/mpact/sim/decoder/decoder_error_listener.h
@@ -34,6 +34,10 @@
  public:
   void semanticError(antlr4::Token *token, absl::string_view msg);
   void semanticWarning(antlr4::Token *token, absl::string_view msg);
+  void semanticError(const std::string &file_name, antlr4::Token *token,
+                     absl::string_view msg);
+  void semanticWarning(const std::string &file_name, antlr4::Token *token,
+                       absl::string_view msg);
   void syntaxError(antlr4::Recognizer *recognizer,
                    antlr4::Token *offendingSymbol, size_t line,
                    size_t charPositionInLine, const std::string &msg,
diff --git a/mpact/sim/decoder/instruction.h b/mpact/sim/decoder/instruction.h
index 01fc4ee..a04ab90 100644
--- a/mpact/sim/decoder/instruction.h
+++ b/mpact/sim/decoder/instruction.h
@@ -78,6 +78,7 @@
   // Getters and setters.
   Opcode *opcode() const { return opcode_; }
   Instruction *child() const { return child_; }
+  Slot *slot() const { return slot_; }
   void set_semfunc_code_string(std::string code_string) {
     semfunc_code_string_ = code_string;
   }
diff --git a/mpact/sim/decoder/instruction_set_visitor.cc b/mpact/sim/decoder/instruction_set_visitor.cc
index 31f9792..579f96c 100644
--- a/mpact/sim/decoder/instruction_set_visitor.cc
+++ b/mpact/sim/decoder/instruction_set_visitor.cc
@@ -110,6 +110,7 @@
   // Create an antlr4 stream from the input stream.
   IsaAntlrParserWrapper parser_wrapper(source_stream);
   error_listener()->set_file_name(file_names[0]);
+  file_names_.push_back(file_names[0]);
   parser_wrapper.parser()->removeErrorListeners();
   parser_wrapper.parser()->addErrorListener(error_listener());
 
@@ -248,17 +249,20 @@
   // Process disasm widths. Only the one in the top level file is used if there
   // are additional ones in included files.
   int count = 0;
-  std::string location;
+  DisasmWidthsCtx *disasm_ctx = nullptr;
   for (auto *decl : declarations) {
+    context_file_map_[decl] = current_file_index_;
     if (decl->disasm_widths() == nullptr) continue;
     if (count > 0) {
       error_listener()->semanticError(
-          nullptr, absl::StrCat("Only one `disasm width` declaration allowed - "
-                                "previous declaration on line: ",
-                                location));
+          decl->disasm_widths()->start,
+          absl::StrCat("Only one `disasm width` declaration allowed - "
+                       "previous declaration on line: ",
+                       disasm_ctx->start->getLine()));
     }
+    disasm_ctx = decl->disasm_widths();
+    context_file_map_[disasm_ctx] = context_file_map_.at(decl);
     VisitDisasmWidthsDecl(decl->disasm_widths());
-    location = absl::StrCat(decl->start->getLine());
     count++;
   }
 
@@ -290,6 +294,7 @@
   for (auto *decl : ctx_vec) {
     if (decl->slot_declaration() != nullptr) {
       auto *slot_ctx = decl->slot_declaration();
+      context_file_map_.insert({slot_ctx, current_file_index_});
       auto name = slot_ctx->slot_name->getText();
       auto ptr = slot_decl_map_.find(name);
       if (ptr != slot_decl_map_.end()) {
@@ -304,6 +309,7 @@
     // Create map from bundle name to bundle ctx.
     if (decl->bundle_declaration() != nullptr) {
       auto *bundle_ctx = decl->bundle_declaration();
+      context_file_map_.insert({bundle_ctx, current_file_index_});
       auto name = bundle_ctx->bundle_name->getText();
       auto ptr = bundle_decl_map_.find(name);
       if (ptr != bundle_decl_map_.end()) {
@@ -319,6 +325,7 @@
     // Create map from isa name to isa ctx.
     if (decl->isa_declaration() != nullptr) {
       auto *isa_ctx = decl->isa_declaration();
+      context_file_map_.insert({isa_ctx, current_file_index_});
       auto name = isa_ctx->instruction_set_name->getText();
       auto ptr = isa_decl_map_.find(name);
       if (ptr != isa_decl_map_.end()) {
@@ -343,6 +350,7 @@
 
     // Process global constants.
     if (decl->constant_def() != nullptr) {
+      context_file_map_.insert({decl->constant_def(), current_file_index_});
       VisitConstantDef(decl->constant_def());
     }
 
@@ -370,7 +378,9 @@
   // Visit the namespace declaration, and the bundle and slot references that
   // are part of the instruction_set declaration.
   VisitNamespaceDecl(ctx->namespace_decl(), instruction_set.get());
+  context_file_map_[ctx->bundle_list()] = context_file_map_.at(ctx);
   VisitBundleList(ctx->bundle_list(), instruction_set->bundle());
+  context_file_map_[ctx->slot_list()] = context_file_map_.at(ctx);
   VisitSlotList(ctx->slot_list(), instruction_set->bundle());
   return instruction_set;
 }
@@ -394,7 +404,7 @@
     // If the name hasn't been seen, flag an error.
     if (iter == bundle_decl_map_.end()) {
       error_listener()->semanticError(
-          bundle_spec->start,
+          file_names_[context_file_map_.at(ctx)], bundle_spec->start,
           absl::StrCat("Reference to undefined bundle: '", bundle_name, "'"));
       continue;
     }
@@ -416,7 +426,7 @@
     // If the slot hasn't been seen, flag an error.
     if (iter == slot_decl_map_.end()) {
       error_listener()->semanticError(
-          slot_spec->start,
+          file_names_[context_file_map_.at(ctx)], slot_spec->start,
           absl::StrCat("Reference to undefined slot: '", slot_name, "'"));
       continue;
     }
@@ -457,6 +467,7 @@
   if (ctx == nullptr) return;
   std::string ident = ctx->ident()->getText();
   std::string type = ctx->template_parameter_type()->getText();
+  context_file_map_.insert({ctx->expression(), context_file_map_.at(ctx)});
   auto *expr = VisitExpression(ctx->expression(), nullptr, nullptr);
   auto status = AddConstant(ident, type, expr);
   if (!status.ok()) {
@@ -504,7 +515,10 @@
     }
   }
   std::string previous_file_name = error_listener()->file_name();
+  int previous_file_index_ = current_file_index_;
   error_listener()->set_file_name(file_name);
+  file_names_.push_back(file_name);
+  current_file_index_ = file_names_.size() - 1;
   // Create an antlr4 stream from the input stream.
   auto *include_parser = new IsaAntlrParserWrapper(&include_file);
   // We need to save the parser state so it's available for analysis after
@@ -517,13 +531,16 @@
   auto declaration_vec =
       include_parser->parser()->include_top_level()->declaration();
   include_file.close();
-  error_listener()->set_file_name(previous_file_name);
   if (error_listener()->syntax_error_count() > 0) {
+    error_listener()->set_file_name(previous_file_name);
+    current_file_index_ = previous_file_index_;
     return;
   }
   include_file_stack_.push_back(file_name);
   PreProcessDeclarations(declaration_vec);
   include_file_stack_.pop_back();
+  error_listener()->set_file_name(previous_file_name);
+  current_file_index_ = previous_file_index_;
 }
 
 void InstructionSetVisitor::VisitBundleDeclaration(
@@ -532,7 +549,9 @@
   Bundle *bundle =
       new Bundle(ctx->bundle_name->getText(), instruction_set, ctx);
   instruction_set->AddBundle(bundle);
+  context_file_map_[ctx->bundle_list()] = context_file_map_.at(ctx);
   VisitBundleList(ctx->bundle_list(), bundle);
+  context_file_map_[ctx->slot_list()] = context_file_map_.at(ctx);
   VisitSlotList(ctx->slot_list(), bundle);
 }
 
@@ -545,7 +564,9 @@
     for (auto const &param : ctx->template_decl()->template_parameter_decl()) {
       auto status = slot->AddTemplateFormal(param->IDENT()->getText());
       if (!status.ok()) {
-        error_listener()->semanticError(param->start, status.message());
+        error_listener()->semanticError(
+            file_names_[context_file_map_.at(slot->ctx())], param->start,
+            status.message());
       }
     }
   }
@@ -558,7 +579,8 @@
       auto slot_iter = slot_decl_map_.find(base_name);
       if (slot_iter == slot_decl_map_.end()) {
         error_listener()->semanticError(
-            base_item->start, absl::StrCat("Undefined base slot: ", base_name));
+            file_names_[context_file_map_.at(ctx)], base_item->start,
+            absl::StrCat("Undefined base slot: ", base_name));
         continue;
       }
       // If the slot hasn't been visited, visit it.
@@ -573,14 +595,14 @@
       if ((template_spec != nullptr) && !base->is_templated()) {
         // Template arguments are present but the slot isn't templated.
         error_listener()->semanticError(
-            base_item->start,
+            file_names_[context_file_map_.at(ctx)], base_item->start,
             absl::StrCat("'", base_name, "' is not a templated slot"));
         continue;
       }
       if ((template_spec == nullptr) && base->is_templated()) {
         // The slot is templated, but no template arguments.
         error_listener()->semanticError(
-            base_item->start,
+            file_names_[context_file_map_.at(ctx)], base_item->start,
             absl::StrCat("Missing template arguments for slot '", base_name,
                          "'"));
         continue;
@@ -591,7 +613,7 @@
         int param_count = base->template_parameters().size();
         if (arg_count != param_count) {
           error_listener()->semanticError(
-              template_spec->start,
+              file_names_[context_file_map_.at(ctx)], template_spec->start,
               absl::StrCat("Wrong number of arguments: ", param_count,
                            " were expected, ", arg_count, " were provided"));
           continue;
@@ -600,10 +622,12 @@
         // Build up the argument vector.
         auto *arguments = new TemplateInstantiationArgs;
         for (auto *template_arg : template_spec->expression()) {
+          context_file_map_.insert({template_arg, context_file_map_.at(ctx)});
           auto *expr = VisitExpression(template_arg, slot, nullptr);
           if (expr == nullptr) {
-            error_listener()->semanticError(template_arg->start,
-                                            "Error in template expression");
+            error_listener()->semanticError(
+                file_names_[context_file_map_.at(ctx)], template_arg->start,
+                "Error in template expression");
             has_error = true;
             break;
           }
@@ -618,13 +642,17 @@
         }
         auto result = slot->AddBase(base, arguments);
         if (!result.ok()) {
-          error_listener()->semanticError(base_item->start, result.message());
+          error_listener()->semanticError(
+              file_names_[context_file_map_.at(ctx)], base_item->start,
+              result.message());
         }
       } else {
         // No template arguments.
         auto result = slot->AddBase(base);
         if (!result.ok()) {
-          error_listener()->semanticError(base_item->start, result.message());
+          error_listener()->semanticError(
+              file_names_[context_file_map_.at(ctx)], base_item->start,
+              result.message());
         }
       }
     }
@@ -637,13 +665,16 @@
   // Add the slot to the ISA.
   instruction_set->AddSlot(slot);
   for (auto *decl_ctx : ctx->const_and_default_decl()) {
+    context_file_map_[decl_ctx] = context_file_map_.at(ctx);
     VisitConstAndDefaultDecls(decl_ctx, slot);
   }
+  context_file_map_[ctx->opcode_list()] = context_file_map_.at(ctx);
   VisitOpcodeList(ctx->opcode_list(), slot);
 }
 
 void InstructionSetVisitor::VisitDisasmWidthsDecl(DisasmWidthsCtx *ctx) {
   for (auto *expr : ctx->expression()) {
+    context_file_map_.insert({expr, context_file_map_.at(ctx)});
     auto *width_expr = VisitExpression(expr, nullptr, nullptr);
     if ((width_expr == nullptr) || (!width_expr->IsConstant())) {
       error_listener()->semanticError(expr->start,
@@ -662,17 +693,21 @@
   if (const_def != nullptr) {  // Constant declaration.
     std::string ident = const_def->ident()->getText();
     std::string type = const_def->template_parameter_type()->getText();
+    context_file_map_.insert(
+        {const_def->expression(), context_file_map_.at(ctx)});
     auto *expr = VisitExpression(const_def->expression(), slot, nullptr);
     if (expr == nullptr) {
       delete expr;
-      error_listener()->semanticError(const_def->expression()->start,
+      error_listener()->semanticError(file_names_[context_file_map_.at(ctx)],
+                                      const_def->expression()->start,
                                       "Error in expression");
       return;
     }
     auto status = slot->AddConstant(ident, type, expr);
     if (!status.ok()) {
       delete expr;
-      error_listener()->semanticError(const_def->ident()->start,
+      error_listener()->semanticError(file_names_[context_file_map_.at(ctx)],
+                                      const_def->ident()->start,
                                       status.message());
     }
     return;
@@ -683,10 +718,12 @@
     return;
   }
   if (ctx->LATENCY() != nullptr) {  // Default latency.
+    context_file_map_.insert({ctx->expression(), context_file_map_.at(ctx)});
     auto *expr = VisitExpression(ctx->expression(), slot, nullptr);
     if (expr == nullptr) {
       delete expr;
-      error_listener()->semanticError(ctx->expression()->start,
+      error_listener()->semanticError(file_names_[context_file_map_.at(ctx)],
+                                      ctx->expression()->start,
                                       "Error in expression");
       return;
     }
@@ -694,6 +731,8 @@
     return;
   }
   if (ctx->ATTRIBUTES() != nullptr) {  // Default attributes.
+    context_file_map_.insert(
+        {ctx->instruction_attribute_list(), context_file_map_.at(ctx)});
     VisitInstructionAttributeList(ctx->instruction_attribute_list(), slot,
                                   nullptr);
     return;
@@ -711,7 +750,8 @@
     // and semantic function for when no valid opcode is found during decode.
     if (slot->default_instruction() != nullptr) {
       error_listener()->semanticError(
-          ctx->start, "Multiple definitions of 'default' opcode");
+          file_names_[context_file_map_.at(ctx)], ctx->start,
+          "Multiple definitions of 'default' opcode");
       return;
     }
     auto *default_instruction = new Instruction(
@@ -722,8 +762,9 @@
       // Disasm spec.
       if (attribute->disasm_spec() != nullptr) {
         if (has_disasm) {
-          error_listener()->semanticError(attribute->start,
-                                          "Duplicate disasm declaration");
+          error_listener()->semanticError(
+              file_names_[context_file_map_.at(ctx)], attribute->start,
+              "Duplicate disasm declaration");
           continue;
         }
         has_disasm = true;
@@ -743,7 +784,8 @@
       // Semfunc spec.
       // If a semfunc has already been declared, signal an error.
       if (has_semfunc) {
-        error_listener()->semanticError(attribute->start,
+        error_listener()->semanticError(file_names_[context_file_map_.at(ctx)],
+                                        attribute->start,
                                         "Duplicate semfunc declaration");
         continue;
       }
@@ -753,7 +795,8 @@
       // opcode.
       if (semfunc_code.size() > 1) {
         error_listener()->semanticError(
-            ctx->start, "Only one semfunc specification per default opcode");
+            file_names_[context_file_map_.at(ctx)], ctx->start,
+            "Only one semfunc specification per default opcode");
         continue;
       }
       std::string string_literal = semfunc_code[0]->getText();
@@ -767,14 +810,15 @@
     } else {
       delete default_instruction;
       error_listener()->semanticError(
-          ctx->start, "Default opcode lacks mandatory semfunc specification");
+          file_names_[context_file_map_.at(ctx)], ctx->start,
+          "Default opcode lacks mandatory semfunc specification");
     }
   }
   if (ctx->resource_details() != nullptr) {
     std::string ident = ctx->ident()->getText();
     if (slot->resource_spec_map().contains(ident)) {
       error_listener()->semanticError(
-          ctx->ident()->start,
+          file_names_[context_file_map_.at(ctx)], ctx->ident()->start,
           absl::StrCat("Resources '", ident, "': duplicate definition"));
       return;
     }
@@ -792,6 +836,7 @@
                                                            Instruction *inst) {
   if (ctx == nullptr) return nullptr;
   if (ctx->negop() != nullptr) {
+    context_file_map_.insert({ctx->expr, context_file_map_.at(ctx)});
     TemplateExpression *expr = VisitExpression(ctx->expr, slot, inst);
     if (expr == nullptr) return nullptr;
     return new TemplateNegate(expr);
@@ -799,8 +844,10 @@
 
   if (ctx->mulop() != nullptr) {
     std::string op = ctx->mulop()->getText();
+    context_file_map_.insert({ctx->lhs, context_file_map_.at(ctx)});
     TemplateExpression *lhs = VisitExpression(ctx->lhs, slot, inst);
     if (lhs == nullptr) return nullptr;
+    context_file_map_.insert({ctx->rhs, context_file_map_.at(ctx)});
     TemplateExpression *rhs = VisitExpression(ctx->rhs, slot, inst);
     if (rhs == nullptr) {
       delete lhs;
@@ -812,8 +859,10 @@
 
   if (ctx->addop() != nullptr) {
     std::string op = ctx->addop()->getText();
+    context_file_map_.insert({ctx->lhs, context_file_map_.at(ctx)});
     TemplateExpression *lhs = VisitExpression(ctx->lhs, slot, inst);
     if (lhs == nullptr) return nullptr;
+    context_file_map_.insert({ctx->rhs, context_file_map_.at(ctx)});
     TemplateExpression *rhs = VisitExpression(ctx->rhs, slot, inst);
     if (rhs == nullptr) {
       delete lhs;
@@ -828,19 +877,22 @@
     auto iter = template_function_evaluators_.find(function);
     if (iter == template_function_evaluators_.end()) {
       error_listener()->semanticError(
-          ctx->start, absl::StrCat("No function '", function, "' supported"));
+          file_names_[context_file_map_.at(ctx)], ctx->start,
+          absl::StrCat("No function '", function, "' supported"));
       return nullptr;
     }
     auto evaluator = iter->second;
     if (ctx->expression().size() != evaluator.arity) {
       error_listener()->semanticError(
-          ctx->start, absl::StrCat("Function '", function, "' takes ",
-                                   evaluator.arity, " parameters, but ",
-                                   ctx->expression().size(), " were given"));
+          file_names_[context_file_map_.at(ctx)], ctx->start,
+          absl::StrCat("Function '", function, "' takes ", evaluator.arity,
+                       " parameters, but ", ctx->expression().size(),
+                       " were given"));
     }
     auto *args = new TemplateInstantiationArgs;
     bool has_error = false;
     for (auto *expr_ctx : ctx->expression()) {
+      context_file_map_.insert({expr_ctx, context_file_map_.at(ctx)});
       auto *expr = VisitExpression(expr_ctx, slot, inst);
       if (expr == nullptr) {
         has_error = true;
@@ -859,6 +911,7 @@
   }
 
   if (ctx->paren_expr != nullptr) {
+    context_file_map_.insert({ctx->paren_expr, context_file_map_.at(ctx)});
     return VisitExpression(ctx->paren_expr, slot, inst);
   }
 
@@ -888,7 +941,7 @@
       auto *op = inst->GetDestOp(ident);
       if (op == nullptr) {
         error_listener()->semanticError(
-            ctx->start,
+            file_names_[context_file_map_.at(ctx)], ctx->start,
             absl::StrCat("'", ident,
                          "' is not a valid destination operand for opcode '",
                          inst->opcode()->name(), "'"));
@@ -901,7 +954,8 @@
       // expr is null, this means that the destination operand has a decode
       // time computed latency. This is a special case that will be addressed
       // later. For now, signal an unsupported error.
-      error_listener()->semanticError(ctx->start,
+      error_listener()->semanticError(file_names_[context_file_map_.at(ctx)],
+                                      ctx->start,
                                       "Decode time evaluation of latency "
                                       "expression not supported for resources");
       return nullptr;
@@ -911,20 +965,24 @@
     if (expr != nullptr) return expr->DeepCopy();
 
     error_listener()->semanticError(
-        ctx->start, absl::StrCat("Unable to evaluate expression: ", "'",
-                                 ctx->getText(), "'"));
+        file_names_[context_file_map_.at(ctx)], ctx->start,
+        absl::StrCat("Unable to evaluate expression: ", "'", ctx->getText(),
+                     "'"));
   }
 
   return nullptr;
 }
 
 DestinationOperand *InstructionSetVisitor::FindDestinationOpInExpression(
-    ExpressionCtx *ctx, const Slot *slot, const Instruction *inst) const {
+    ExpressionCtx *ctx, const Slot *slot, const Instruction *inst) {
   if (ctx == nullptr) return nullptr;
   if (ctx->negop() != nullptr) {
+    context_file_map_.insert({ctx->expr, context_file_map_.at(ctx)});
     return FindDestinationOpInExpression(ctx->expr, slot, inst);
   }
   if ((ctx->mulop() != nullptr) || (ctx->addop() != nullptr)) {
+    context_file_map_.insert({ctx->lhs, context_file_map_.at(ctx)});
+    context_file_map_.insert({ctx->rhs, context_file_map_.at(ctx)});
     auto *lhs = FindDestinationOpInExpression(ctx->lhs, slot, inst);
     auto *rhs = FindDestinationOpInExpression(ctx->rhs, slot, inst);
     if (lhs == nullptr) return rhs;
@@ -938,6 +996,7 @@
     return nullptr;
   }
   if (ctx->paren_expr != nullptr) {
+    context_file_map_.insert({ctx->paren_expr, context_file_map_.at(ctx)});
     return FindDestinationOpInExpression(ctx->paren_expr, slot, inst);
   }
   if (ctx->NUMBER() != nullptr) {
@@ -947,6 +1006,7 @@
     DestinationOperand *dest_op = nullptr;
     DestinationOperand *tmp_op;
     for (auto *expr_ctx : ctx->expression()) {
+      context_file_map_.insert({expr_ctx, context_file_map_.at(ctx)});
       tmp_op = FindDestinationOpInExpression(expr_ctx, slot, inst);
       if (dest_op == nullptr) {
         dest_op = tmp_op;
@@ -997,7 +1057,9 @@
         absl::Status status =
             slot->AppendInheritedInstruction(inst_ptr, base_slot.arguments);
         if (!status.ok()) {
-          error_listener()->semanticError(ctx->start, status.message());
+          error_listener()->semanticError(
+              file_names_[context_file_map_.at(ctx)], ctx->start,
+              status.message());
         }
       }
     }
@@ -1008,7 +1070,8 @@
   for (auto *inst : instruction_vec) {
     absl::Status status = slot->AppendInstruction(inst);
     if (!status.ok()) {
-      error_listener()->semanticError(ctx->start, status.message());
+      error_listener()->semanticError(file_names_[context_file_map_.at(ctx)],
+                                      ctx->start, status.message());
     }
   }
 }
@@ -1039,8 +1102,9 @@
       inst->ClearDisasmFormat();
       // Signal error if there is more than one disassembly spec.
       if (has_disasm) {
-        error_listener()->semanticError(attribute_ctx->start,
-                                        "Multiple disasm specifications");
+        error_listener()->semanticError(
+            file_names_[context_file_map_.at(slot->ctx())],
+            attribute_ctx->start, "Multiple disasm specifications");
         continue;
       }
       has_disasm = true;
@@ -1051,8 +1115,9 @@
         format.erase(0, 1);
         auto status = ParseDisasmFormat(format, inst);
         if (!status.ok()) {
-          error_listener()->semanticError(attribute_ctx->disasm_spec()->start,
-                                          status.message());
+          error_listener()->semanticError(
+              file_names_[context_file_map_.at(slot->ctx())],
+              attribute_ctx->disasm_spec()->start, status.message());
           has_disasm = false;
           break;
         }
@@ -1066,8 +1131,9 @@
       inst->ClearSemfuncCodeString();
       // Signal error if there is more than one semantic function spec.
       if (has_semfunc) {
-        error_listener()->semanticError(attribute_ctx->start,
-                                        "Multiple semfunc specifications");
+        error_listener()->semanticError(
+            file_names_[context_file_map_.at(slot->ctx())],
+            attribute_ctx->start, "Multiple semfunc specifications");
         continue;
       }
       has_semfunc = true;
@@ -1081,8 +1147,9 @@
       inst->ClearResourceSpecs();
       // Signal error if there is more than one resource specification.
       if (has_resources) {
-        error_listener()->semanticError(attribute_ctx->start,
-                                        "Multiple resource specifications");
+        error_listener()->semanticError(
+            file_names_[context_file_map_.at(slot->ctx())],
+            attribute_ctx->start, "Multiple resource specifications");
         continue;
       }
       has_resources = true;
@@ -1097,8 +1164,9 @@
       inst->ClearAttributeSpecs();
       // Signal error if there is more than one attribute specification.
       if (has_attributes) {
-        error_listener()->semanticError(attribute_ctx->start,
-                                        "Multiple attribute specifications");
+        error_listener()->semanticError(
+            file_names_[context_file_map_.at(slot->ctx())],
+            attribute_ctx->start, "Multiple attribute specifications");
         continue;
       }
       has_attributes = true;
@@ -1109,8 +1177,9 @@
     }
 
     // Unknown attribute type.
-    error_listener()->semanticError(attribute_ctx->start,
-                                    "Unknown attribute type");
+    error_listener()->semanticError(
+        file_names_[context_file_map_.at(slot->ctx())], attribute_ctx->start,
+        "Unknown attribute type");
   }
 }
 
@@ -1121,12 +1190,14 @@
     std::string name = attribute->IDENT()->getText();
     if (attributes.find(name) != attributes.end()) {
       error_listener()->semanticError(
-          attribute->start,
+          file_names_[context_file_map_.at(slot->ctx())], attribute->start,
           absl::StrCat("Duplicate attribute name '", name, "' in list"));
       continue;
     }
     InstructionSet::AddAttributeName(name);
     if (attribute->expression() != nullptr) {
+      context_file_map_.insert(
+          {attribute->expression(), context_file_map_.at(slot->ctx())});
       auto *expr = VisitExpression(attribute->expression(), slot, inst);
       attributes.emplace(name, expr);
       continue;
@@ -1158,8 +1229,9 @@
   // should be one the opcode and one for each child opcode.
   for (auto *sem_func : semfunc_spec->STRING_LITERAL()) {
     if (child == nullptr) {
-      error_listener()->semanticWarning(sem_func->getSymbol(),
-                                        "Ignoring extra semfunc spec");
+      error_listener()->semanticWarning(
+          file_names_[context_file_map_.at(inst->slot()->ctx())],
+          sem_func->getSymbol(), "Ignoring extra semfunc spec");
       break;
     }
     std::string literal = sem_func->getText();
@@ -1170,6 +1242,7 @@
   // Are there fewer specifier strings than child instructions?
   if (child != nullptr) {
     error_listener()->semanticError(
+        file_names_[context_file_map_.at(inst->slot()->ctx())],
         semfunc_spec->start,
         absl::StrCat("Fewer semfunc specifiers than expected for opcode '",
                      inst->opcode()->name(), "'"));
@@ -1186,7 +1259,7 @@
     if (iter == slot->resource_spec_map().end()) {
       // This should never happen.
       error_listener()->semanticError(
-          ctx->start,
+          file_names_[context_file_map_.at(slot->ctx())], ctx->start,
           absl::StrCat("Internal error: Undefined resources name: '", name,
                        "'"));
       return;
@@ -1222,6 +1295,8 @@
   if (resource_item->begin_cycle == nullptr) {
     begin_expr = new TemplateConstant(0);
   } else {
+    context_file_map_.insert(
+        {resource_item->begin_cycle, context_file_map_.at(slot->ctx())});
     tmp_op =
         FindDestinationOpInExpression(resource_item->begin_cycle, slot, inst);
     if (tmp_op != nullptr) {
@@ -1229,12 +1304,15 @@
         dest_op = tmp_op;
       } else if (dest_op != tmp_op) {
         error_listener()->semanticError(
+            file_names_[context_file_map_.at(slot->ctx())],
             resource_item->start,
             "Resource reference can only reference a single "
             "destination operand");
         return return_value;
       }
     }
+    context_file_map_.insert(
+        {resource_item->begin_cycle, context_file_map_.at(slot->ctx())});
     begin_expr = VisitExpression(resource_item->begin_cycle, slot, inst);
   }
 
@@ -1248,6 +1326,8 @@
       end_expr = new TemplateConstant(0);
     }
   } else {
+    context_file_map_.insert(
+        {resource_item->end_cycle, context_file_map_.at(slot->ctx())});
     tmp_op =
         FindDestinationOpInExpression(resource_item->end_cycle, slot, inst);
     if (tmp_op != nullptr) {
@@ -1262,6 +1342,8 @@
         return return_value;
       }
     }
+    context_file_map_.insert(
+        {resource_item->end_cycle, context_file_map_.at(slot->ctx())});
     end_expr = VisitExpression(resource_item->end_cycle, slot, inst);
   }
   auto *ref = new ResourceReference(resource, dest_op, begin_expr, end_expr);
@@ -1362,7 +1444,7 @@
     // If there is no base slot, this is an error.
     if (slot->base_slots().empty()) {
       error_listener()->semanticError(
-          opcode_ctx->deleted,
+          file_names_[context_file_map_.at(slot->ctx())], opcode_ctx->deleted,
           absl::StrCat("Invalid deleted opcode '", opcode_name, "', slot '",
                        slot->name(), "' does not inherit from a base slot"));
       return;
@@ -1376,7 +1458,7 @@
     // If the opcode was not defined in any of the base slots, it is an error.
     if (!found) {
       error_listener()->semanticError(
-          opcode_ctx->deleted,
+          file_names_[context_file_map_.at(slot->ctx())], opcode_ctx->deleted,
           absl::StrCat("Base slot does not define or inherit opcode '",
                        opcode_name, "'"));
       return;
@@ -1396,13 +1478,13 @@
     // Multiple inheritance is not supported.
     if (found == 0) {
       error_listener()->semanticError(
-          opcode_ctx->deleted,
+          file_names_[context_file_map_.at(slot->ctx())], opcode_ctx->deleted,
           absl::StrCat("Base slot does not define or inherit opcode '",
                        opcode_name, "'"));
       return;
     } else if (found > 1) {
       error_listener()->semanticError(
-          opcode_ctx->deleted,
+          file_names_[context_file_map_.at(slot->ctx())], opcode_ctx->deleted,
           absl::StrCat("Multiple inheritance of opcodes is not supported: ",
                        opcode_name));
       return;
@@ -1414,8 +1496,9 @@
   // This is a new opcode, so let's create it. Signal failure if error.
   absl::StatusOr<Opcode *> result = opcode_factory->CreateOpcode(opcode_name);
   if (!result.ok()) {
-    error_listener()->semanticError(opcode_ctx->name,
-                                    result.status().message());
+    error_listener()->semanticError(
+        file_names_[context_file_map_.at(slot->ctx())], opcode_ctx->name,
+        result.status().message());
     return;
   }
 
@@ -1507,6 +1590,8 @@
       // expression, by '*' (wildcard), or omitted, in which case it
       // defaults to 1.
       if (dest_op->expression() != nullptr) {
+        context_file_map_.insert(
+            {dest_op->expression(), context_file_map_.at(slot->ctx())});
         child->opcode()->AppendDestOp(
             ident, VisitExpression(dest_op->expression(), slot, child));
       } else if (dest_op->wildcard != nullptr) {
@@ -1542,7 +1627,7 @@
       std::string name = ident_ctx->getText();
       if (range_variable_names.contains(name)) {
         error_listener()->semanticError(
-            assign_ctx->start,
+            file_names_[context_file_map_.at(slot->ctx())], assign_ctx->start,
             absl::StrCat("Duplicate binding variable name '", name, "'"));
         continue;
       }
@@ -1555,7 +1640,7 @@
       if (!RE2::PartialMatch(ctx->generator_opcode_spec_list()->getText(),
                              range_info->range_regexes.back())) {
         error_listener()->semanticWarning(
-            assign_ctx->start,
+            file_names_[context_file_map_.at(slot->ctx())], assign_ctx->start,
             absl::StrCat("Unreferenced binding variable '", name, "'"));
       }
     }
@@ -1606,6 +1691,7 @@
     auto ident = input_text.substr(start_pos, end_pos - start_pos);
     if (!range_variable_names.contains(ident)) {
       error_listener()->semanticError(
+          file_names_[context_file_map_.at(slot->ctx())],
           ctx->generator_opcode_spec_list()->start,
           absl::StrCat("Undefined binding variable '", ident, "'"));
     }
diff --git a/mpact/sim/decoder/instruction_set_visitor.h b/mpact/sim/decoder/instruction_set_visitor.h
index 4515b8f..5889a21 100644
--- a/mpact/sim/decoder/instruction_set_visitor.h
+++ b/mpact/sim/decoder/instruction_set_visitor.h
@@ -141,8 +141,9 @@
   void ParseIncludeFile(antlr4::ParserRuleContext *ctx,
                         const std::string &file_name,
                         const std::vector<std::string> &dirs);
-  DestinationOperand *FindDestinationOpInExpression(
-      ExpressionCtx *ctx, const Slot *slot, const Instruction *inst) const;
+  DestinationOperand *FindDestinationOpInExpression(ExpressionCtx *ctx,
+                                                    const Slot *slot,
+                                                    const Instruction *inst);
   void PerformOpcodeOverrides(
       absl::flat_hash_set<OpcodeSpecCtx *> overridden_ops_set, Slot *slot);
   void PreProcessDeclarations(const std::vector<DeclarationCtx *> &ctx_vec);
@@ -209,6 +210,11 @@
   // Include file strings.
   absl::btree_set<std::string> include_files_;
 
+  int current_file_index_ = 0;
+  // Vector of file names.
+  std::vector<std::string> file_names_;
+  // Map from context pointer to file index.
+  absl::flat_hash_map<antlr4::ParserRuleContext *, int> context_file_map_;
   // Include file roots.
   std::vector<std::string> include_dir_vec_;
   // Keep track of files that are included in case there is recursive includes.