blob: 7183800d7c89cec4c6f835d7c53a42d3769acb1c [file] [log] [blame]
Austin Schuh208337d2022-01-01 14:29:11 -08001/*
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.
18YY_DECL;
19
20
21struct pio_assembler {
22public:
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
41 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
51 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
78 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