diff options
| author | Miquel Sabaté Solà <mikisabate@gmail.com> | 2024-12-24 16:48:16 +0100 |
|---|---|---|
| committer | Miquel Sabaté Solà <mikisabate@gmail.com> | 2025-01-07 16:38:54 +0100 |
| commit | 9b5e5aa6d36a550bed84f85df8e1e46fcf9765e1 (patch) | |
| tree | 9748bd1059bb24fd5fb204ff9d91ae7531632beb /lib/xixanta/src/opcodes.rs | |
| parent | f3c6b02fb2f2957b9b896c34d05abe75263c3f60 (diff) | |
| download | tools.nes-9b5e5aa6d36a550bed84f85df8e1e46fcf9765e1.tar.gz tools.nes-9b5e5aa6d36a550bed84f85df8e1e46fcf9765e1.zip | |
Add the .repeat control statement
This is a control statement which acts similarly as .proc/.macro/.scope,
in which an inner block is allocated for it. Hence, all the previous
work from 1f8a6becc7cd ("parser: Implement block bodies") and
ec8b709fa24c ("Implement block bodies inside of the assembler") make
this one out possible, as .repeat statements don't have an identifier
that can be used for hashing.
From the parser perspective this introduction raises two new things.
First of all this control statement also needed a differentiation
between the amount of required arguments, and the allowed ones, since
there is a second optional argument to it. And second, even the
identifier is not given, we have to generate one so to add a context for
it. This was at first not needed, but introducing .repeat-only variables
means that we have to have inner contexts which need to be named somehow
so we can retrieve the context later when picking up the value for them
again.
This last thing brought the need for a new dependency: rand. This is
used to generate a random string to identify the .repeat block.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
Diffstat (limited to 'lib/xixanta/src/opcodes.rs')
| -rw-r--r-- | lib/xixanta/src/opcodes.rs | 51 |
1 files changed, 34 insertions, 17 deletions
diff --git a/lib/xixanta/src/opcodes.rs b/lib/xixanta/src/opcodes.rs index 24cbade..6c0aa0d 100644 --- a/lib/xixanta/src/opcodes.rs +++ b/lib/xixanta/src/opcodes.rs @@ -54,11 +54,26 @@ pub struct ShortEntry { // pub affected_on_page: bool, // } +/// The representation of a Control statement/expression. #[derive(Debug)] pub struct Control { + /// Type of control statement/expression. pub control_type: ControlType, - pub has_identifier: bool, - pub required_args: Option<usize>, + + /// Whether there is an expected identifier here, either by the parser or + /// from an assembler perspective (e.g. 'Foo' in '.proc Foo'). A None value + /// means that there is no identifier expected, Some(true) means that the + /// identifier is not real but has to be created on the fly by the parser + /// (e.g. .repeat). + pub has_identifier: Option<bool>, + + /// Minimum and maximum number of arguments accepted by this control + /// statement, or None if undefined (e.g. a .macro which has an undefined + /// number of arguments). + pub required_args: Option<(usize, usize)>, + + /// True if the context has to change after evaluating this control + /// statement. pub touches_context: bool, } @@ -716,21 +731,23 @@ lazy_static! { pub static ref CONTROL_FUNCTIONS: HashMap<String, Control> = { let mut functions = HashMap::new(); - functions.insert(String::from(".hibyte"), Control { control_type: ControlType::Hibyte, has_identifier: false, required_args: Some(1), touches_context: false }); - functions.insert(String::from(".lobyte"), Control { control_type: ControlType::Lobyte, has_identifier: false, required_args: Some(1), touches_context: false }); - functions.insert(String::from(".macro"), Control { control_type: ControlType::StartMacro, has_identifier: true, required_args: None, touches_context: true }); - functions.insert(String::from(".proc"), Control { control_type: ControlType::StartProc, has_identifier: true, required_args: Some(0), touches_context: true }); - functions.insert(String::from(".scope"), Control { control_type: ControlType::StartScope, has_identifier: true, required_args: Some(0), touches_context: true }); - functions.insert(String::from(".endscope"), Control { control_type: ControlType::EndScope, has_identifier: false, required_args: Some(0), touches_context: true }); - functions.insert(String::from(".endproc"), Control { control_type: ControlType::EndProc, has_identifier: false, required_args: Some(0), touches_context: true }); - functions.insert(String::from(".endmacro"), Control { control_type: ControlType::EndMacro, has_identifier: false, required_args: Some(0), touches_context: true }); - functions.insert(String::from(".segment"), Control { control_type: ControlType::Segment, has_identifier: false, required_args: Some(1), touches_context: false }); - functions.insert(String::from(".byte"), Control { control_type: ControlType::Byte, has_identifier: false, required_args: None, touches_context: false }); - functions.insert(String::from(".db"), Control { control_type: ControlType::Byte, has_identifier: false, required_args: None, touches_context: false }); - functions.insert(String::from(".word"), Control { control_type: ControlType::Word, has_identifier: false, required_args: None, touches_context: false }); - functions.insert(String::from(".dw"), Control { control_type: ControlType::Word, has_identifier: false, required_args: None, touches_context: false }); - functions.insert(String::from(".addr"), Control { control_type: ControlType::Addr, has_identifier: false, required_args: None, touches_context: false }); - functions.insert(String::from(".incbin"), Control { control_type: ControlType::IncBin, has_identifier: false, required_args: Some(1), touches_context: false }); + functions.insert(String::from(".hibyte"), Control { control_type: ControlType::Hibyte, has_identifier: None, required_args: Some((1, 1)), touches_context: false }); + functions.insert(String::from(".lobyte"), Control { control_type: ControlType::Lobyte, has_identifier: None, required_args: Some((1, 1)), touches_context: false }); + functions.insert(String::from(".macro"), Control { control_type: ControlType::StartMacro, has_identifier: Some(false), required_args: None, touches_context: true }); + functions.insert(String::from(".proc"), Control { control_type: ControlType::StartProc, has_identifier: Some(false), required_args: Some((0, 0)), touches_context: true }); + functions.insert(String::from(".scope"), Control { control_type: ControlType::StartScope, has_identifier: Some(false), required_args: Some((0, 0)), touches_context: true }); + functions.insert(String::from(".endscope"), Control { control_type: ControlType::EndScope, has_identifier: None, required_args: Some((0, 0)), touches_context: true }); + functions.insert(String::from(".endproc"), Control { control_type: ControlType::EndProc, has_identifier: None, required_args: Some((0, 0)), touches_context: true }); + functions.insert(String::from(".endmacro"), Control { control_type: ControlType::EndMacro, has_identifier: None, required_args: Some((0, 0)), touches_context: true }); + functions.insert(String::from(".segment"), Control { control_type: ControlType::Segment, has_identifier: None, required_args: Some((1, 1)), touches_context: false }); + functions.insert(String::from(".byte"), Control { control_type: ControlType::Byte, has_identifier: None, required_args: None, touches_context: false }); + functions.insert(String::from(".db"), Control { control_type: ControlType::Byte, has_identifier: None, required_args: None, touches_context: false }); + functions.insert(String::from(".word"), Control { control_type: ControlType::Word, has_identifier: None, required_args: None, touches_context: false }); + functions.insert(String::from(".dw"), Control { control_type: ControlType::Word, has_identifier: None, required_args: None, touches_context: false }); + functions.insert(String::from(".addr"), Control { control_type: ControlType::Addr, has_identifier: None, required_args: None, touches_context: false }); + functions.insert(String::from(".incbin"), Control { control_type: ControlType::IncBin, has_identifier: None, required_args: Some((1, 1)), touches_context: false }); + functions.insert(String::from(".repeat"), Control { control_type: ControlType::StartRepeat, has_identifier: Some(true), required_args: Some((1, 2)), touches_context: true }); + functions.insert(String::from(".endrepeat"), Control { control_type: ControlType::EndRepeat, has_identifier: None, required_args: None, touches_context: true }); functions }; |
