From 0de38e9ad0608dcdafb85885ac3dd03d94892724 Mon Sep 17 00:00:00 2001 From: Erhan BARIS Date: Wed, 14 Aug 2024 21:35:30 +0200 Subject: [PATCH] .byte directive --- src/ast.rs | 66 ++++++++++++++++++++++++++++++++++++-------- src/code_gen.rs | 28 ++++++++++++++----- src/main.rs | 45 ++---------------------------- src/options.rs | 26 +++++++++-------- src/parser.rs | 20 +++++++------- src/tests/generic.rs | 3 ++ 6 files changed, 104 insertions(+), 84 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index c08e5f5..c60b9d8 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,6 +1,6 @@ use std::{cell::Cell, marker::PhantomData}; -use crate::{context::Context, opcode::{ModeType, BRANCH_INSTS, INSTS_SIZE, JUMP_INSTS}, options::{CompilerOptionEnum, CompilerValue, CompilerValueType, OPTIONS, OPTION_ENUMS, OPTION_MODES}, parser::{Token, TokenInfo}, tool::{print_error, upper_case}}; +use crate::{context::Context, opcode::{ModeType, BRANCH_INSTS, INSTS_SIZE, JUMP_INSTS}, options::{DirectiveEnum, DirectiveType, DirectiveValue, DIRECTIVE_ENUMS, OPTIONS, OPTION_MODES}, parser::{Token, TokenInfo, TokenType}, tool::{print_error, upper_case}}; #[derive(Debug, Copy, Clone)] pub enum BranchType { @@ -16,7 +16,7 @@ pub enum Ast<'a> { Instr(usize, u16, ModeType), InstrRef(usize, &'a [u8]), Branch(&'a [u8], BranchType), - CompilerOption(CompilerOptionEnum, CompilerValue<'a>), + Directive(DirectiveEnum, DirectiveValue<'a>), Assign(&'a [u8], u16, ModeType) } @@ -81,12 +81,18 @@ impl<'a> AstGenerator<'a> { } } - fn eat(&self)-> Result { + fn eat(&self) -> Result { self.empty_check()?; self.index.set(self.index.get() + 1); Ok(self.index.get() - 1) } + fn dec(&self) -> Result<(), AstGeneratorError> { + self.empty_check()?; + self.index.set(self.index.get() - 1); + Ok(()) + } + fn peek(&self)-> Result { self.empty_check()?; Ok(self.index.get()) @@ -110,6 +116,42 @@ impl<'a> AstGenerator<'a> { Ok(()) } + fn eat_if(&self, context: &Context<'a>, expected: TokenType) -> Option { + let token_index = match self.peek() { + Ok(token_index) => token_index, + Err(_) => return None + }; + + let token = &context.tokens.borrow()[token_index]; + let token_type: TokenType = TokenType::from(token.token); + + match token_type == expected { + true => { + self.index.set(self.index.get() + 1); + Some(token_index) + } + false => None + } + } + + fn eat_if_string(&self, context: &Context<'a>) -> Option<&'a [u8]> { + let index = self.eat_if(context, TokenType::String)?; + let token = &context.tokens.borrow()[index]; + match token.token { + Token::String(string) => Some(string), + _ => None + } + } + + fn eat_if_number(&self, context: &Context<'a>) -> Option<(u16, ModeType)> { + let index = self.eat_if(context, TokenType::Number)?; + let token = &context.tokens.borrow()[index]; + match token.token { + Token::Number(number, mode) => Some((number, mode)), + _ => None + } + } + fn eat_number(&self, context: &Context<'a>) -> Result<(u16, ModeType), AstGeneratorError> { let token_index= self.eat()?; let token = &context.tokens.borrow()[token_index]; @@ -146,27 +188,27 @@ impl<'a> AstGenerator<'a> { } } - fn generate_compiler_option(&self, context: &Context<'a>, token_index: usize, option: &'a [u8]) -> Result<(), AstGeneratorError> { + fn generate_directive(&self, context: &Context<'a>, token_index: usize, option: &'a [u8]) -> Result<(), AstGeneratorError> { let option = upper_case(option); if let Some(position) = OPTIONS.iter().position(|item| *item == &option[..]) { let modes = OPTION_MODES[position]; - let compiler_option_type = OPTION_ENUMS[position]; + let directive_type = DIRECTIVE_ENUMS[position]; let mut found = false; self.cleanup_space(context)?; for mode in modes.iter() { match mode { - CompilerValueType::Number => { - if let Ok((number, mode)) = self.eat_number(context) { - context.add_ast(token_index, Ast::CompilerOption(compiler_option_type, CompilerValue::Number(number, mode))); + DirectiveType::Number => { + if let Some((number, mode)) = self.eat_if_number(context) { + context.add_ast(token_index, Ast::Directive(directive_type, DirectiveValue::Number(number, mode))); found = true; break; } }, - CompilerValueType::String => { - if let Ok(string) = self.eat_string(context) { - context.add_ast(token_index,Ast::CompilerOption(compiler_option_type, CompilerValue::String(string))); + DirectiveType::String => { + if let Some(string) = self.eat_if_string(context) { + context.add_ast(token_index,Ast::Directive(directive_type, DirectiveValue::String(string))); found = true; break; } @@ -251,7 +293,7 @@ impl<'a> AstGenerator<'a> { match &context.tokens.borrow().get(token_index).map(|item| item.token) { Some(Token::Instr(positon)) => self.generate_code_block(&context, token_index, *positon)?, Some(Token::Keyword(keyword)) => self.generate_assign(&context, token_index, keyword)?, - Some(Token::CompilerOption(option)) => self.generate_compiler_option(&context, token_index, option)?, + Some(Token::Directive(option)) => self.generate_directive(&context, token_index, option)?, Some(Token::Comment(_)) => (), Some(Token::Branch(name)) => self.generate_branch(&context, token_index, name, BranchType::Generic)?, Some(Token::Number(_, _)) => return Err(AstGeneratorError::syntax_issue(&context, token_index, "Number not expected")), diff --git a/src/code_gen.rs b/src/code_gen.rs index 8388833..64b891a 100644 --- a/src/code_gen.rs +++ b/src/code_gen.rs @@ -7,7 +7,7 @@ use strum_macros::EnumDiscriminants; use crate::context::Context; use crate::tool::print_error; -use crate::{ast::{Ast, BranchType}, opcode::{ModeType, MODES}, options::{CompilerOptionEnum, CompilerValue}}; +use crate::{ast::{Ast, BranchType}, opcode::{ModeType, MODES}, options::{DirectiveEnum, DirectiveValue}}; #[derive(Error, Debug)] pub enum CodeGeneratorError { @@ -26,7 +26,9 @@ pub enum CodeGeneratorError { #[error("IO Error ({0})")] IOError(#[from] std::io::Error), #[error("Text convertion issue ({0})")] - Utf8Error(#[from] Utf8Error) + Utf8Error(#[from] Utf8Error), + #[error("Unsupported number format")] + UnsupportedNumberFormat } #[derive(Debug, PartialEq, Copy, Clone)] @@ -209,13 +211,13 @@ impl<'a> CodeGenerator<'a> { Ok(()) } - fn configure_compiler(&mut self, target: &mut Vec, option: CompilerOptionEnum, value: CompilerValue<'a>) -> Result<(), CodeGeneratorError> { + fn configure_directive(&mut self, target: &mut Vec, option: DirectiveEnum, value: DirectiveValue<'a>) -> Result<(), CodeGeneratorError> { match option { - CompilerOptionEnum::Org => self.start_point = value.as_u16(), - CompilerOptionEnum::Incbin => { + DirectiveEnum::Org => self.start_point = value.as_u16(), + DirectiveEnum::Incbin => { let file_path = match value { - CompilerValue::String(name) => name, + DirectiveValue::String(name) => name, _ => return Err(CodeGeneratorError::StringExpected) }; @@ -237,6 +239,18 @@ impl<'a> CodeGenerator<'a> { } } }, + DirectiveEnum::Byte => { + match value { + DirectiveValue::String(value) => value.into_iter().for_each(|byte| target.push(*byte)), + DirectiveValue::Number(number, mode) => { + match mode { + ModeType::Relative | ModeType::Absolute => self.push_number(target, number, mode)?, + ModeType::ZeroPage => self.push_number(target, number, mode)?, + _ => return Err(CodeGeneratorError::UnsupportedNumberFormat) + } + } + }; + }, }; Ok(()) } @@ -256,7 +270,7 @@ impl<'a> CodeGenerator<'a> { Some(Ast::Instr(position, number, mode)) => self.generate_instr(&mut context.target, *position, *number, *mode)?, Some(Ast::InstrRef(position, reference)) => self.generate_instr_reference(&mut context.target, *position, *reference)?, Some(Ast::Branch(name, branch_type)) => self.generate_branch(&mut context.target, name, *branch_type)?, - Some(Ast::CompilerOption(option, value)) => self.configure_compiler(&mut context.target, *option, *value)?, + Some(Ast::Directive(option, value)) => self.configure_directive(&mut context.target, *option, *value)?, Some(Ast::Assign(name, number, mode)) => self.configure_assign(*name, *number, *mode)?, None => return Err(CodeGeneratorError::InternalError) }; diff --git a/src/main.rs b/src/main.rs index c961e6e..3016c58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,54 +15,13 @@ use parser::Parser; fn main() { - let data = br#"; to assemble: vasm6502_oldstyle -Fbin -dotdir clock.s -o clock.out - - .org $6000 - -; kernel routines -IOSAVE = $FF4A ; save the A, X, and Y registers -IOREST = $FF3F ; restore the A, X, and Y registers - -; kernal addresses -KYBD = $C000 ; keyboard -KBSTROBE = $C010 ; keyboard strobe to clear the keyboard register -IRQ_VECTOR_L = $03FE -IRQ_VECTOR_H = $03FF -INT_ENABLE = $C05C ; sets annuciater 2 low - -; constants -LEFT_ARROW = $88 ; keyboard left arrow -RIGHT_ARROW = $95 ; keyboard right arrow -CLOCK_X_OFFSET = 1 ; clock offset on x-axis -CLOCK_Y_OFFSET = 8 ; clock offset on y-axis -TICKS_PER_MIN = 95 ; ticks per minute from pendulum clock - -; zero page addresses -tmp = $1D ; general purpose for storing temporary address (2 bytes) -row_ptr = $1F ; pointer to a row address in screen memory (2 bytes) -char_x = $21 ; x position of the number to draw (1 byte) -char_y = $22 ; y position of the number to draw (1 byte) -stor_x = $23 ; (1 byte) -stor_y = $24 ; (1 byte) -ticks = $25 ; counter for pendulum clock ticks (1 byte) -blink = $26 ; on/off toggle for hours/minutes separator (1 byte) -hours = $27 ; the hours part of the current time (1 byte) -minutes = $28 ; the minutes part of the current time (1 byte) - -;======================================================================= -; Wait for key press -; M: increases minutes -; H: increases hours -; Any other key exits -;======================================================================= -main_loop: bidt KYBD ; wait for a key press to adjust time - bpl main_loop - lda KYBD"#; + let data = br#".byte $ff"#; let context = Context::new(data); let mut parser = Parser::new(context); parser.parse().unwrap(); + println!("{:?}", &parser.context.tokens); parser.friendly_dump(); let context = parser.context; diff --git a/src/options.rs b/src/options.rs index bc8db3e..34fddd5 100644 --- a/src/options.rs +++ b/src/options.rs @@ -3,31 +3,33 @@ use strum_macros::EnumDiscriminants; use crate::opcode::ModeType; #[derive(Debug, PartialEq, Copy, Clone)] -pub enum CompilerOptionEnum { +pub enum DirectiveEnum { Org, - Incbin + Incbin, + Byte } #[derive(Debug, PartialEq, Copy, Clone)] #[derive(EnumDiscriminants)] -#[strum_discriminants(name(CompilerValueType))] -pub enum CompilerValue<'a> { +#[strum_discriminants(name(DirectiveType))] +pub enum DirectiveValue<'a> { Number(u16, ModeType), String(&'a [u8]) } -impl<'a> CompilerValue<'a> { +impl<'a> DirectiveValue<'a> { pub fn as_u16(&self) -> u16 { match self { - CompilerValue::Number(number, _) => *number, - CompilerValue::String(_) => 0 + DirectiveValue::Number(number, _) => *number, + DirectiveValue::String(_) => 0 } } } -pub const OPTIONS: [&[u8]; 2] = [b"ORG", b"INCBIN"]; -pub const ORG_TYPES: [CompilerValueType; 1] = [CompilerValueType::Number]; -pub const INCBIN_TYPES: [CompilerValueType; 1] = [CompilerValueType::String]; +pub const OPTIONS: [&[u8]; 3] = [b"ORG", b"INCBIN", b"BYTE"]; +pub const ORG_TYPES: [DirectiveType; 1] = [DirectiveType::Number]; +pub const INCBIN_TYPES: [DirectiveType; 1] = [DirectiveType::String]; +pub const BYTE_TYPES: [DirectiveType; 2] = [DirectiveType::String, DirectiveType::Number]; -pub const OPTION_MODES: [&[CompilerValueType]; 2] = [&ORG_TYPES, &INCBIN_TYPES]; -pub const OPTION_ENUMS: [CompilerOptionEnum; 2] = [CompilerOptionEnum::Org, CompilerOptionEnum::Incbin]; +pub const OPTION_MODES: [&[DirectiveType]; 3] = [&ORG_TYPES, &INCBIN_TYPES, &BYTE_TYPES]; +pub const DIRECTIVE_ENUMS: [DirectiveEnum; 3] = [DirectiveEnum::Org, DirectiveEnum::Incbin, DirectiveEnum::Byte]; diff --git a/src/parser.rs b/src/parser.rs index ad58bc4..8090ab7 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -36,7 +36,7 @@ pub enum Token<'a> { Instr(usize), Keyword(&'a [u8]), String(&'a [u8]), - CompilerOption(&'a [u8]), + Directive(&'a [u8]), Comment(&'a [u8]), Assign, Branch(&'a [u8]), @@ -63,7 +63,7 @@ pub enum ParseError { InvalidNumberFormat, InvalidCommentFormat, InvalidKeyword, - InvalidCompilerOption, + InvalidDirective, InvalidString } @@ -200,7 +200,7 @@ impl<'a> Parser<'a> { b'(' => self.parse_indirect(), b'#' => self.parse_immediate(), b'a'..=b'z' | b'A'..=b'Z' => self.parse_keyword(), - b'.' => self.parse_compiler_options(), + b'.' => self.parse_directive(), b'"' => self.parse_string(), b';' => self.parse_comment(), b'=' => self.parse_assign(), @@ -466,8 +466,8 @@ impl<'a> Parser<'a> { Ok(Token::String(&self.context.source[start..self.index-1])) } - fn parse_compiler_options(&mut self) -> Result, ParseError> { - self.eat_expected(b'.', ParseError::InvalidCompilerOption)?; + fn parse_directive(&mut self) -> Result, ParseError> { + self.eat_expected(b'.', ParseError::InvalidDirective)?; let start = self.index; let mut valid = false; @@ -486,24 +486,24 @@ impl<'a> Parser<'a> { break; }, b' ' | b'\t' | b'\n' | b'\r' => break, - _ => return Err(ParseError::InvalidCompilerOption), + _ => return Err(ParseError::InvalidDirective), }; self.eat()?; } Err(ParseError::OutOfScope) => break, - _ => return Err(ParseError::InvalidCompilerOption), + _ => return Err(ParseError::InvalidDirective), }; } if !valid { - return Err(ParseError::InvalidCompilerOption); + return Err(ParseError::InvalidDirective); } if branch { return Ok(Token::BranchNext(&self.context.source[start..self.index - 1])); } - Ok(Token::CompilerOption(&self.context.source[start..self.index])) + Ok(Token::Directive(&self.context.source[start..self.index])) } fn parse_comment(&mut self) -> Result, ParseError> { @@ -563,7 +563,7 @@ impl<'a> Parser<'a> { let type_name = match ast.token { Token::Instr(_) => "INSTR", Token::Keyword(_) => "KEYWORD", - Token::CompilerOption(_) => "OPTION", + Token::Directive(_) => "OPTION", Token::Comment(_) => "COMMENT", Token::Branch(_) => "BRANCH", Token::Number(_, _) => "NUMBER", diff --git a/src/tests/generic.rs b/src/tests/generic.rs index 795ae84..9096e67 100644 --- a/src/tests/generic.rs +++ b/src/tests/generic.rs @@ -162,6 +162,9 @@ IOREST = $FF3F ; restore the A, X, and Y registers lda IOSAVE LDx IOREST"#, &[0xad, 0x4a, 0xff, 0xae, 0x3f, 0xff])] +#[case(br#".byte "abcd""#, &[0x61, 0x62, 0x63, 0x64])] +#[case(br#".byte $ff"#, &[0xFF])] +#[case(br#".byte $ff .byte "abcd""#, &[0xFF, 0x61, 0x62, 0x63, 0x64])] fn check_codes(#[case] data: &'_ [u8], #[case] codes: &'_ [u8]) { let context = Context::new(data);