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