summaryrefslogtreecommitdiff
path: root/Source/Core/Common/Assembler/GekkoParser.h
blob: d3b270258ddd158350f47c1af0345726d339e0bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <optional>
#include <string>
#include <string_view>

#include "Common/Assembler/AssemblerShared.h"
#include "Common/Assembler/GekkoLexer.h"
#include "Common/CommonTypes.h"

namespace Common::GekkoAssembler::detail
{
class ParsePlugin;

struct ParseState
{
  ParseState(std::string_view input_str, ParsePlugin& plugin);

  bool HasToken(TokenType tp) const;
  void ParseToken(TokenType tp);
  void EmitErrorHere(std::string&& message);

  Lexer lexer;
  ParsePlugin& plugin;

  std::optional<AssemblerError> error;
  bool eof;
};

enum class AsmOp
{
  Or,
  Xor,
  And,
  Lsh,
  Rsh,
  Add,
  Sub,
  Mul,
  Div,
  Neg,
  Not
};

enum class Terminal
{
  Hex,
  Dec,
  Oct,
  Bin,
  Flt,
  Str,
  Id,
  GPR,
  FPR,
  SPR,
  CRField,
  Lt,
  Gt,
  Eq,
  So,
  Dot,
  NumLabFwd,
  NumLabBwd,
};

enum class ParenType
{
  Normal,
  RelConv,
};

// Overridable plugin class supporting a series of skeleton functions which get called when
// the parser parses a given point of interest
class ParsePlugin
{
public:
  ParsePlugin() : m_owner(nullptr) {}
  virtual ~ParsePlugin() = default;

  void SetOwner(ParseState* o) { m_owner = o; }
  void ForwardError(AssemblerError&& err) { m_owner_error = std::move(err); }
  std::optional<AssemblerError>& Error() { return m_owner_error; }

  virtual void PostParseAction() {}

  // Nonterminal callouts
  // Pre occurs prior to the head nonterminal being parsed
  // Post occurs after the nonterminal has been fully parsed
  virtual void OnDirectivePre(GekkoDirective directive) {}
  virtual void OnDirectivePost(GekkoDirective directive) {}
  virtual void OnInstructionPre(const ParseInfo& mnemonic_info, bool extended) {}
  virtual void OnInstructionPost(const ParseInfo& mnemonic_info, bool extended) {}
  virtual void OnOperandPre() {}
  virtual void OnOperandPost() {}
  virtual void OnResolvedExprPre() {}
  virtual void OnResolvedExprPost() {}

  // Operator callouts
  // All occur after the relevant operands have been parsed
  virtual void OnOperator(AsmOp operation) {}

  // Individual token callouts
  // All occur prior to the token being parsed
  // Due to ambiguity of some tokens, an explicit operation is provided
  virtual void OnTerminal(Terminal type, const AssemblerToken& val) {}
  virtual void OnHiaddr(std::string_view id) {}
  virtual void OnLoaddr(std::string_view id) {}
  virtual void OnOpenParen(ParenType type) {}
  virtual void OnCloseParen(ParenType type) {}
  virtual void OnError() {}
  virtual void OnLabelDecl(std::string_view name) {}
  virtual void OnNumericLabelDecl(std::string_view name, u32 parse_num) {}
  virtual void OnVarDecl(std::string_view name) {}

protected:
  ParseState* m_owner;
  std::optional<AssemblerError> m_owner_error;
};

// Parse the provided input with a plugin to handle what to do with certain points of interest
// e.g. Convert to an IR for generating final machine code, picking up syntactical information
void ParseWithPlugin(ParsePlugin* plugin, std::string_view input);
}  // namespace Common::GekkoAssembler::detail