diff --git a/.gitignore b/.gitignore index c15232a..4fe3144 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ !swlc !LICENSE !build - +*.exe # Added by cargo # diff --git a/src/main.rs b/src/main.rs index 00c376d..f9286d3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,8 +17,8 @@ use std::{fs, env::args, process::{exit, Command}, collections::HashMap, /// Enum representing possible target types // TODO(#2): parse target types (-t/--target) -#[derive(PartialEq, Eq)] -enum Target { +#[derive(PartialEq, Eq, Debug, Clone, Copy)] +pub enum Target { Linux, #[allow(unused)] Bsd, @@ -161,7 +161,7 @@ fn main() { // let (contents, links, links_libs) = preprocessor::preprocess(contents, filename.clone()); // construct parser - let mut parser = parser::Parser::new(contents, filename.clone(), verbose).unwrap_or_else(|a| { + let mut parser = parser::Parser::new(contents, filename.clone(), verbose, target).unwrap_or_else(|a| { eprintln!("Error reading file: {}", a); exit(1); }); @@ -281,6 +281,9 @@ fn main() { let mut outfile = path; outfile.push_str(&name); + if target == Target::Windows { + outfile.push_str(".exe"); + } let mut linked_files = parser.links.clone(); let linked_libs = parser.linked_libs.clone(); diff --git a/src/parser.rs b/src/parser.rs index 40df67e..97d314c 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,6 +1,6 @@ use std::fs; -use crate::preprocessor; +use crate::{preprocessor, Target}; use {crate::{util, util::{indent, PrimitiveType, Type, BinaryOp, UnaryOp, ErrorLevel, Op, Error}, error}, std::{io, collections::HashMap}, crate::lexer::{TokenType, Lexer, Token}}; @@ -9,6 +9,7 @@ pub struct Parser { pub lexer : Lexer, pub links : Vec, pub linked_libs : Vec, + pub target : Target, } #[derive(Debug, Clone)] @@ -463,12 +464,13 @@ macro_rules! err_add { } impl Parser { - pub fn new(src: Vec, filename: String, verbose: usize) -> Result { - let (contents, l, ll) = preprocessor::preprocess(src, filename.clone()); + pub fn new(src: Vec, filename: String, verbose: usize, target: Target) -> Result { + let (contents, l, ll) = preprocessor::preprocess(src, filename.clone(), target); Ok(Parser { lexer: Lexer::new(filename, contents, verbose)?, links: l, linked_libs: ll, + target, }) } @@ -1169,7 +1171,7 @@ impl Parser { } let contents = fs::read_to_string(filename.clone()).expect("File read error: ").chars().collect(); - let mut file_parser = match Parser::new(contents, filename.clone(), verbose) { + let mut file_parser = match Parser::new(contents, filename.clone(), verbose, self.target) { Ok(a) => a, Err(e) => { errors.push((ErrorLevel::Err, error!(self.lexer, token.pos, "ERROR during loading of file: {e}"))); diff --git a/src/preprocessor.rs b/src/preprocessor.rs index 8213606..cd9fcf8 100644 --- a/src/preprocessor.rs +++ b/src/preprocessor.rs @@ -1,4 +1,4 @@ -use crate::{COLOR_RED, COLOR_GREEN, COLOR_RESET}; +use crate::{COLOR_RED, COLOR_GREEN, COLOR_RESET, Target}; use std::process::exit; fn pos_to_line_char(source: Vec, pos: usize) -> (usize, usize) { @@ -42,11 +42,18 @@ macro_rules! parse_str { }; } -pub fn preprocess(file: Vec, filename: String) -> (Vec, Vec, Vec) { +#[derive(PartialEq, Eq)] +enum Action { + Delete, + Ignore +} + +pub fn preprocess(file: Vec, filename: String, tgt: Target) -> (Vec, Vec, Vec) { let mut i : usize = 0; let mut to_skip : Vec<(usize, usize)> = vec![]; let mut links : Vec = vec![]; let mut links_libs : Vec = vec![]; + let mut action_stack : Vec<(usize, Action)> = vec![]; while i < file.len() { let ch = file[i]; @@ -75,9 +82,9 @@ pub fn preprocess(file: Vec, filename: String) -> (Vec, Vec, continue; } else if ch == '#' { let dir_start = i + 1; - while file[i] != ' ' {i += 1}; + while !file[i].is_whitespace() {i += 1}; let directive = file.iter().skip(dir_start).take(i - dir_start).collect::(); - while file[i] != ' ' {i += 1}; + while !file[i].is_whitespace() {i += 1}; to_skip.push((dir_start - 1, i - dir_start + 1)); match directive.as_str() { @@ -103,14 +110,60 @@ pub fn preprocess(file: Vec, filename: String) -> (Vec, Vec, ); exit(1); }, + "target" => { + let target_ = match parse_str!(file, i, dir_start, filename) { + Some(a) => a, + None => continue, + }; + let target = match target_.as_str() { + "linux" => Target::Linux, + "windows" => Target::Windows, + _ => { + let (l, c) = pos_to_line_char(file.clone(), dir_start); + eprintln!("{COLOR_RED}error: {COLOR_GREEN}{file}:{line}:{ch}: {COLOR_RESET}invalid target {target_}", + file = filename, + line = l+1, + ch = c+1, + ); + exit(1); + } + }; + + if tgt != target { + action_stack.push((i+1, Action::Delete)); + } else { + action_stack.push((i+1, Action::Ignore)); + } + }, + "end" => { + if action_stack.is_empty() { + let (l, c) = pos_to_line_char(file.clone(), dir_start); + eprintln!("{COLOR_RED}error: {COLOR_GREEN}{file}:{line}:{ch}: {COLOR_RESET}#end does not end anything", + file = filename, + line = l+1, + ch = c+1, + ); + exit(1); + } + let (ind, action) = action_stack.pop().unwrap(); + if action == Action::Delete { + for (v, item) in file.iter().enumerate().take(i).skip(ind) { + if *item != '\n' { + to_skip.push((v, 1)); + } + } + } + } _ => { let (l, c) = pos_to_line_char(file.clone(), dir_start); - eprintln!("{file}:{line}:{ch}: Invalid preprocesser \ + eprintln!("{COLOR_RED}error: {COLOR_GREEN}{file}:{line}:{ch}: {COLOR_RESET}Invalid preprocesser \ directive `{directive}`", file = filename, line = l+1, ch = c+1, - )} + ); + exit(1); + } } } i += 1; @@ -119,8 +172,8 @@ pub fn preprocess(file: Vec, filename: String) -> (Vec, Vec, to_skip.sort(); let mut new_file = file; for (a, l) in to_skip.iter().rev() { - for _ in 0..*l { - new_file.remove(*a); + for i in 0..*l { + new_file[a+i] = ' '; } } diff --git a/swl/linux.swl b/swl/linux.swl index 0214591..0428992 100644 --- a/swl/linux.swl +++ b/swl/linux.swl @@ -249,3 +249,47 @@ func sleep(long millis) { }; syscall2(35, as[long, ref time], 0l); } + + +// runs a given command +// ----- +// args: +// command <- the command +func system(string command) { + [char*] args = alloc_array(8*4); + args[0] = "/usr/bin/sh".to_cstr(); + args[1] = "-c".to_cstr(); + args[2] = command.to_cstr(); + args[3] = as[char*, 0]; + + int pid = fork(); + if (pid == 0) { + execve("/usr/bin/sh".to_cstr(), args, env()); + exit(0); + } + while (true) { + long ret = syscall4(61, as[long, pid], 0l, 0l, 0l); + if (ret <= 0l) { + break; + } + sleep(10l); + } +} + + +// prints a given string to stdout +// ------ +// args: +// str <- the string to print +func print([char] str) { + write(1l, arr2addr(str), arrlen(str)); +} + +// prints a given string to stderr +// ------ +// args: +// str <- the string to print +func eprint([char] str) { + write(2l, arr2addr(str), arrlen(str)); +} + diff --git a/swl/std.swl b/swl/std.swl index 96504e9..5677490 100644 --- a/swl/std.swl +++ b/swl/std.swl @@ -1,7 +1,12 @@ /* SWL STANDARD LIBRARY */ -#error "TODO" +#target "linux" include "linux.swl"; +#end + +#target "windows" +include "windows.swl"; +#end // used intrinsics @@ -172,6 +177,23 @@ func strcpy_off(string a, int a_off, string b, int b_off) { /** IO UTILS **/ +// prints a given string to stdout, followed by a line feed +// ------ +// args: +// str <- the string to print +func println([char] str) { + print(str); + print("\n"); +} + +// prints a given string to stderr, followed by a line feed +// ------ +// args: +// str <- the string to print +func eprintln([char] str) { + eprint(str); + eprint("\n"); +} func get_line([char] buf) -> int { int bytes = 0; @@ -198,66 +220,6 @@ func getch() -> char { } } -// prints a given string to stdout -// ------ -// args: -// str <- the string to print -func print([char] str) { - write(1l, arr2addr(str), arrlen(str)); -} - -// prints a given string to stderr -// ------ -// args: -// str <- the string to print -func eprint([char] str) { - write(2l, arr2addr(str), arrlen(str)); -} - -// prints a given string to stdout, followed by a line feed -// ------ -// args: -// str <- the string to print -func println([char] str) { - print(str); - print("\n"); -} - -// prints a given string to stderr, followed by a line feed -// ------ -// args: -// str <- the string to print -func eprintln([char] str) { - print(str); - print("\n"); -} - - - -// runs a given command -// ----- -// args: -// command <- the command -func system(string command) { - [char*] args = alloc_array(8*4); - args[0] = "/usr/bin/sh".to_cstr(); - args[1] = "-c".to_cstr(); - args[2] = command.to_cstr(); - args[3] = as[char*, 0]; - - int pid = fork(); - if (pid == 0) { - execve("/usr/bin/sh".to_cstr(), args, env()); - exit(0); - } - while (true) { - long ret = syscall4(61, as[long, pid], 0l, 0l, 0l); - if (ret <= 0l) { - break; - } - sleep(10l); - } -} /** STRING UTILS **/ diff --git a/swl/windows.swl b/swl/windows.swl new file mode 100644 index 0000000..c356238 --- /dev/null +++ b/swl/windows.swl @@ -0,0 +1,72 @@ +/** SYSCALL WRAPPER FUNCTIONS (LINUX x86_64) **/ + +alias string = [char]; + +intrinsic convert as __unsafe_convert(_a i) -> unchecked; +intrinsic dereference as arrlen([unchecked] str) -> int; +intrinsic str_to_ptr as arr2addr([unchecked] str) -> long; +intrinsic convert as ptr2arr(long ptr) -> [unchecked]; + +func print(string str) {}; +func eprint(string str) {}; + + +// opens a file with a given path, mode, and flags +// ------ +// args: +// path <- the path to the file to open +// mode <- the mode to open the file with +// flags <- the flags to open the file with +// returns: the file descriptor of the opened file +func open(string path, long flags, long mode) -> long { + <- -1l; +} + +// closes a given file descriptor +// ------ +// args: +// fd <- the file descriptor to close +func close(long fd) { +} + +// exits the current process +// ------ +// args: +// status <- the status to exit with +func exit(int status) { + +} + + +/* OTHER UTILITY FUNCTIONS */ + +#link_lib "msvcrt" +extern func malloc(int size) -> long; +extern func free(long ptr); + + +// reads contents from stdin in a given array buffer, until it is full +// ------ +// args: +// buf <- the buffer +func input([char] buf) -> int { + <- -1; +// <- read(0, arr2addr(buf), arrlen(buf)); +} + +// replaces the current process with the given process +// ----- +// args: +// filename <- the filename of the process +// argv <- args of the process +// envp <- environment of the process +func execve(char *filename, [char*] argv, [char*] envp) { +} + +// sleeps a given amount of milliseconds +// ----- +// args: +// millis <- the time +func sleep(long millis) { + +} diff --git a/swlc b/swlc index 109e5d3..e571923 100755 Binary files a/swlc and b/swlc differ