Skip to content

Commit

Permalink
.byte directive
Browse files Browse the repository at this point in the history
  • Loading branch information
erhanbaris committed Aug 14, 2024
1 parent 36441a8 commit 0de38e9
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 84 deletions.
66 changes: 54 additions & 12 deletions src/ast.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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)
}

Expand Down Expand Up @@ -81,12 +81,18 @@ impl<'a> AstGenerator<'a> {
}
}

fn eat(&self)-> Result<usize, AstGeneratorError> {
fn eat(&self) -> Result<usize, AstGeneratorError> {
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<usize, AstGeneratorError> {
self.empty_check()?;
Ok(self.index.get())
Expand All @@ -110,6 +116,42 @@ impl<'a> AstGenerator<'a> {
Ok(())
}

fn eat_if(&self, context: &Context<'a>, expected: TokenType) -> Option<usize> {
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];
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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")),
Expand Down
28 changes: 21 additions & 7 deletions src/code_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)]
Expand Down Expand Up @@ -209,13 +211,13 @@ impl<'a> CodeGenerator<'a> {
Ok(())
}

fn configure_compiler(&mut self, target: &mut Vec<u8>, option: CompilerOptionEnum, value: CompilerValue<'a>) -> Result<(), CodeGeneratorError> {
fn configure_directive(&mut self, target: &mut Vec<u8>, 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)
};

Expand All @@ -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(())
}
Expand All @@ -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)
};
Expand Down
45 changes: 2 additions & 43 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
26 changes: 14 additions & 12 deletions src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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];
20 changes: 10 additions & 10 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]),
Expand All @@ -63,7 +63,7 @@ pub enum ParseError {
InvalidNumberFormat,
InvalidCommentFormat,
InvalidKeyword,
InvalidCompilerOption,
InvalidDirective,
InvalidString
}

Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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<Token<'a>, ParseError> {
self.eat_expected(b'.', ParseError::InvalidCompilerOption)?;
fn parse_directive(&mut self) -> Result<Token<'a>, ParseError> {
self.eat_expected(b'.', ParseError::InvalidDirective)?;
let start = self.index;

let mut valid = false;
Expand All @@ -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<Token<'a>, ParseError> {
Expand Down Expand Up @@ -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",
Expand Down
3 changes: 3 additions & 0 deletions src/tests/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit 0de38e9

Please sign in to comment.