Added simple C preprocessor style macros to enable support for multiple system types

This commit is contained in:
MCorange 2023-03-28 02:09:41 +03:00
parent db83d6d9c1
commit 4213986202
15 changed files with 203 additions and 29 deletions

View File

@ -391,7 +391,10 @@ pub fn compile(tokens: &[Operator], args: &Args, folders: &Folders) -> Result<i3
writeln!(writer, " push rax")?;
ti += 1;
},
OpType::Instruction(InstructionType::None) | OpType::Keyword(KeywordType::Macro) | OpType::Keyword(KeywordType::Include) => unreachable!()
OpType::Instruction(InstructionType::None) |
OpType::Keyword(KeywordType::Macro) |
OpType::Keyword(KeywordType::Include) |
OpType::Preprocessor(_) => unreachable!()
}
}
writeln!(writer, "addr_{ti}:")?;

View File

@ -7,7 +7,7 @@ use crate::info;
pub fn linux_x86_64_compile_and_link(folders: &Folders, quiet: bool) -> Result<()> {
let nasm_args = [
"-felf64",
"-fwin32",
folders.of_a.to_str().unwrap(),
"-o",
folders.of_o.to_str().unwrap()
@ -16,7 +16,11 @@ pub fn linux_x86_64_compile_and_link(folders: &Folders, quiet: bool) -> Result<(
let ld_args = [
folders.of_o.to_str().unwrap(),
"-o",
folders.of_c.to_str().unwrap()
folders.of_c.to_str().unwrap(),
"-L",
"C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Lib",
"-l",
"kernel32"
];

View File

@ -9,7 +9,6 @@ use crate::constants::InstructionType;
use super::Folders;
pub fn compile(tokens: &[Operator], args: &Args, folders: &Folders) -> Result<i32>{
let file = fs::File::create(&folders.of_a)?;
let mut writer = BufWriter::new(&file);
@ -389,7 +388,10 @@ pub fn compile(tokens: &[Operator], args: &Args, folders: &Folders) -> Result<i3
writeln!(writer, " push rax")?;
ti += 1;
},
OpType::Instruction(InstructionType::None) | OpType::Keyword(KeywordType::Macro) | OpType::Keyword(KeywordType::Include) => unreachable!()
OpType::Instruction(InstructionType::None) |
OpType::Keyword(KeywordType::Macro) |
OpType::Keyword(KeywordType::Include) |
OpType::Preprocessor(_) => unreachable!()
}
}
writeln!(writer, "addr_{ti}:")?;

View File

@ -60,10 +60,20 @@ pub enum KeywordType {
Include,
}
#[derive(Debug, Clone, PartialEq)]
pub enum PreprocessorType {
IfDefined,
IfNotDefined,
Else,
EndIf,
Define
}
#[derive(Debug, Clone, PartialEq)]
pub enum OpType {
Keyword(KeywordType),
Instruction(InstructionType)
Instruction(InstructionType),
Preprocessor(PreprocessorType)
}
#[derive(Debug, Clone)]
@ -132,7 +142,12 @@ impl OpType {
OpType::Instruction(InstructionType::Syscall4) => "syscall4",
OpType::Instruction(InstructionType::Syscall5) => "syscall5",
OpType::Instruction(InstructionType::Syscall6) => "syscall6",
OpType::Instruction(InstructionType::None) => "None"
OpType::Instruction(InstructionType::None) => "None",
OpType::Preprocessor(PreprocessorType::IfDefined) => "#ifdef",
OpType::Preprocessor(PreprocessorType::IfNotDefined) => "#ifndef",
OpType::Preprocessor(PreprocessorType::Else) => "#else",
OpType::Preprocessor(PreprocessorType::EndIf) => "#endif",
OpType::Preprocessor(PreprocessorType::Define) => "#define",
}.to_string()
}
}

View File

@ -272,7 +272,10 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
todo!();
// ti += 1;
},
OpType::Instruction(InstructionType::None) | OpType::Keyword(KeywordType::Macro) | OpType::Keyword(KeywordType::Include) => unreachable!()
OpType::Instruction(InstructionType::None) |
OpType::Keyword(KeywordType::Macro) |
OpType::Keyword(KeywordType::Include) |
OpType::Preprocessor(_) => unreachable!()
}
}

View File

@ -7,10 +7,13 @@ mod lexer;
mod preprocessor;
use std::fs;
use clap::Parser;
use constants::targets;
/*
TODO: add simple macro support on vscode syntax highlighting
*/
pub const DEFAULT_OUT_FILE: &str = "a.out";
pub const DEFAULT_INCLUDES: [&str;2] = [
"./include",

View File

@ -1,6 +1,6 @@
use std::ops::Deref;
use crate::{constants::{Operator, OpType, Token, TokenType, Loc, KeywordType, InstructionType}, lerror};
use crate::{constants::{Operator, OpType, Token, TokenType, Loc, KeywordType, InstructionType, PreprocessorType}, lerror};
use color_eyre::Result;
use eyre::eyre;
@ -156,6 +156,12 @@ pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType {
"syscall4" => OpType::Instruction(InstructionType::Syscall4),
"syscall5" => OpType::Instruction(InstructionType::Syscall5),
"syscall6" => OpType::Instruction(InstructionType::Syscall6),
"#ifdef" => OpType::Preprocessor(PreprocessorType::IfDefined),
"#ifndef" => OpType::Preprocessor(PreprocessorType::IfNotDefined),
"#else" => OpType::Preprocessor(PreprocessorType::Else),
"#endif" => OpType::Preprocessor(PreprocessorType::EndIf),
"#define" => OpType::Preprocessor(PreprocessorType::Define),
_ => OpType::Instruction(InstructionType::None)
}

View File

@ -4,11 +4,22 @@ use std::path::PathBuf;
use color_eyre::Result;
use eyre::eyre;
use crate::constants::{Token, Loc, OpType, TokenType, KeywordType, InstructionType};
use crate::constants::{Token, Loc, OpType, TokenType, KeywordType, InstructionType, PreprocessorType};
use crate::lexer::lex;
use crate::{lerror, lnote, Args, warn};
use crate::parser::lookup_word;
fn get_predefined_basic_macros(args: &Args) -> Vec<String> {
let mut a: Vec<String> = Vec::new();
if args.target.as_str() == crate::constants::targets::WIN32_X86_64 {
a.push("__win32__".to_string());
} else
if args.target.as_str() == crate::constants::targets::LINUX_X86_64 {
a.push("__linux__".to_string());
}
a
}
#[derive(Debug)]
pub struct Macro {
pub loc: Loc,
@ -18,7 +29,11 @@ pub struct Macro {
pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{
let mut program: Vec<Token> = Vec::new();
let mut macros: HashMap<String, Macro> = HashMap::new();
let mut basic_macros: Vec<String> = get_predefined_basic_macros(args);
//* predefined basic macros
let mut rtokens = tokens;
rtokens.reverse();
while !rtokens.is_empty() {
@ -71,8 +86,6 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{
macros.insert(macro_name.text, macr);
}
_ if op_type == OpType::Keyword(KeywordType::Include) => {
@ -114,6 +127,141 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{
}
_ if op_type == OpType::Preprocessor(PreprocessorType::Define) => {
if rtokens.is_empty(){
lerror!(&token.loc(), "Basic macro contents not found, expected {} but found nothing", TokenType::Word.human());
return Err(eyre!(""));
}
let basic_macro_name = rtokens.pop().unwrap();
if basic_macro_name.typ != TokenType::Word {
lerror!(&basic_macro_name.loc(), "Bad basic macro contents, expected {} but found {}", TokenType::Word.human(), basic_macro_name.typ.human());
return Err(eyre!(""));
}
let word = lookup_word(&basic_macro_name.text, &basic_macro_name.loc());
if word != OpType::Instruction(InstructionType::None) {
lerror!(&basic_macro_name.loc(), "Basic macro contents cannot be a built in word, got '{}'", word.human());
return Err(eyre!(""));
}
basic_macros.push(basic_macro_name.text);
}
_ if op_type == OpType::Preprocessor(PreprocessorType::IfDefined) => {
if rtokens.is_empty(){
lerror!(&token.loc(), "Basic macro contents not found, expected {} but found nothing", TokenType::Word.human());
return Err(eyre!(""));
}
let basic_macro_name = rtokens.pop().unwrap();
let exists = basic_macros.contains(&basic_macro_name.text);
#[allow(unused_assignments)]
let mut skip = false;
let mut skip_this = false;
let mut els = false;
skip = if !exists { true } else { false };
while !rtokens.is_empty() {
let token = rtokens.pop().unwrap();
let op_typ = lookup_word(&token.text, &token.loc());
if exists {
if op_typ == OpType::Preprocessor(PreprocessorType::Else) {
if els {
todo!();
}
els = true;
skip = true;
}
} else {
if op_typ == OpType::Preprocessor(PreprocessorType::Else) {
if els {
todo!();
}
els = true;
skip = false;
skip_this = true;
}
}
if op_typ == OpType::Preprocessor(PreprocessorType::EndIf) {
break;
}
if !skip {
#[allow(unused_assignments)]
if skip_this {
skip_this = false;
} else {
program.push(token);
}
}
}
},
_ if op_type == OpType::Preprocessor(PreprocessorType::IfNotDefined) => {
if rtokens.is_empty(){
lerror!(&token.loc(), "Basic macro contents not found, expected {} but found nothing", TokenType::Word.human());
return Err(eyre!(""));
}
let basic_macro_name = rtokens.pop().unwrap();
let exists = basic_macros.contains(&basic_macro_name.text);
#[allow(unused_assignments)]
let mut skip = false;
let mut skip_this = false;
let mut els = false;
skip = if exists { true } else { false };
while !rtokens.is_empty() {
let token = rtokens.pop().unwrap();
let op_typ = lookup_word(&token.text, &token.loc());
if !exists {
if op_typ == OpType::Preprocessor(PreprocessorType::Else) {
if els {
todo!();
}
els = true;
skip = true;
}
} else {
if op_typ == OpType::Preprocessor(PreprocessorType::Else) {
if els {
todo!();
}
els = true;
skip = false;
skip_this = true;
}
}
if op_typ == OpType::Preprocessor(PreprocessorType::EndIf) {
break;
}
if !skip {
#[allow(unused_assignments)]
if skip_this {
skip_this = false;
} else {
program.push(token);
}
}
}
},
_ if op_type == OpType::Preprocessor(PreprocessorType::Else) ||
op_type == OpType::Preprocessor(PreprocessorType::EndIf) => {
unreachable!()
},
_ => {
program.push(token);
}

BIN
test

Binary file not shown.

BIN
test.exe

Binary file not shown.

View File

@ -1 +1,3 @@
' ' print
#ifdef __win32__
69
#endif

View File

@ -36,14 +36,10 @@ print:
global _start
_start:
addr_0:
;; -- push int 32
mov rax, 32
;; -- push int 69
mov rax, 69
push rax
addr_1:
;; -- print
pop rdi
call print
addr_2:
mov rax, 60
mov rdi, 0
syscall

BIN
test.o

Binary file not shown.

View File

@ -1 +0,0 @@
gftdesd5ryutfgyhibugtf6r4

View File

@ -1,7 +0,0 @@
34 35 + print
800 380 - print
10 5 * print
40 5 / print