pio_assembler.h 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. /*
  2. * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #ifndef _PIO_ASSEMBLER_H
  7. #define _PIO_ASSEMBLER_H
  8. #include <algorithm>
  9. #include "parser.hpp"
  10. #include "output_format.h"
  11. // Give Flex the prototype of yylex we want ...
  12. # define YY_DECL \
  13. yy::parser::symbol_type yylex (pio_assembler& pioasm)
  14. // ... and declare it for the parser's sake.
  15. YY_DECL;
  16. struct pio_assembler {
  17. public:
  18. using syntax_error = yy::parser::syntax_error;
  19. using location_type = yy::parser::location_type;
  20. std::shared_ptr<program> dummy_global_program;
  21. std::vector<program> programs;
  22. int error_count = 0;
  23. pio_assembler();
  24. std::shared_ptr<output_format> format;
  25. // The name of the file being parsed.
  26. std::string source;
  27. // name of the output file or "-" for stdout
  28. std::string dest;
  29. std::vector<std::string> options;
  30. int write_output();
  31. bool add_program(const yy::location &l, const std::string &name) {
  32. if (std::find_if(programs.begin(), programs.end(), [&](const program &p) { return p.name == name; }) ==
  33. programs.end()) {
  34. programs.emplace_back(this, l, name);
  35. return true;
  36. } else {
  37. return false;
  38. }
  39. }
  40. program &get_dummy_global_program() {
  41. if (!dummy_global_program) {
  42. dummy_global_program = std::shared_ptr<program>(new program(this, yy::location(&source), ""));
  43. }
  44. return *dummy_global_program;
  45. }
  46. program &get_current_program(const location_type &l, const std::string &requiring_program,
  47. bool before_any_instructions = false, bool disallow_global = true) {
  48. if (programs.empty()) {
  49. if (disallow_global) {
  50. std::stringstream msg;
  51. msg << requiring_program << " is invalid outside of a program";
  52. throw syntax_error(l, msg.str());
  53. }
  54. return get_dummy_global_program();
  55. }
  56. auto &p = programs[programs.size() - 1];
  57. if (before_any_instructions && !p.instructions.empty()) {
  58. std::stringstream msg;
  59. msg << requiring_program << " must preceed any program instructions";
  60. throw syntax_error(l, msg.str());
  61. }
  62. return p;
  63. }
  64. // note p may be null for global symbols only
  65. std::shared_ptr<symbol> get_symbol(const std::string &name, const program *p) {
  66. const auto &i = get_dummy_global_program().symbols.find(name);
  67. if (i != get_dummy_global_program().symbols.end())
  68. return i->second;
  69. if (p) {
  70. const auto &i2 = p->symbols.find(name);
  71. if (i2 != p->symbols.end())
  72. return i2->second;
  73. }
  74. return nullptr;
  75. }
  76. std::vector<compiled_source::symbol> public_symbols(program &program);
  77. int generate(std::shared_ptr<output_format> _format, const std::string &_source, const std::string &_dest,
  78. const std::vector<std::string> &_options = std::vector<std::string>());
  79. // Handling the scanner.
  80. void scan_begin();
  81. void scan_end();
  82. // The token's location used by the scanner.
  83. yy::location location;
  84. };
  85. #endif