Initial commit
This commit is contained in:
		
						commit
						a005400477
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| /target | ||||
| /archive | ||||
| /bin | ||||
							
								
								
									
										7
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| # This file is automatically @generated by Cargo. | ||||
| # It is not intended for manual editing. | ||||
| version = 3 | ||||
| 
 | ||||
| [[package]] | ||||
| name = "labast" | ||||
| version = "1.0.1" | ||||
							
								
								
									
										14
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| [package] | ||||
| name = "labast" | ||||
| version = "1.0.1" | ||||
| authors = [ "n3tael" ] | ||||
| edition = "2021" | ||||
| description = "A zero-dependencies Labaski interpreter written in Rust." | ||||
| readme = "README.md" | ||||
| license = "MIT" | ||||
| publish = false | ||||
| 
 | ||||
| [profile.dev] | ||||
| overflow-checks = false | ||||
| 
 | ||||
| [dependencies] | ||||
							
								
								
									
										21
									
								
								LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| MIT License | ||||
| 
 | ||||
| Copyright (c) 2024 n3tael | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
							
								
								
									
										5
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| # Labast | ||||
| A zero-dependencies Labaski interpreter written in Rust. Fully supports [Labashki specs 1.4.1](./SPECIFICATION.md). | ||||
| 
 | ||||
| ## Examples | ||||
| See `example-scripts` directory. | ||||
							
								
								
									
										51
									
								
								SPECIFICATION.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								SPECIFICATION.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| # Labaski specification | ||||
| Last update: 2024-02-05 | ||||
| 
 | ||||
| Программа состоит из команд в формате `ИНСТРУКЦИЯ АРГУМЕНТ` (assembler-like) | ||||
| 
 | ||||
| Аргумент всегда должен быть `uint16` (`unsigned short`, `u16`) | ||||
| 
 | ||||
| Все данные которые программа использует хранятся в стеке, сам стек это массив из этих `unsigned short`'ов | ||||
| 
 | ||||
| Размер стека без разницы, но желательно минимум 256 | ||||
| 
 | ||||
| Выполнение программы начинается либо с начала файла, либо с лейбла 0, если он есть | ||||
| 
 | ||||
| Почти каждая инструкция которые читает что-то стека должна POP'ать прочитаннное значение | ||||
| 
 | ||||
| Если название инструкции начинается с #, то парсер программы должен прочитать аргумент к инструкции как строку(до первого пробела) | ||||
| 
 | ||||
| ## Инструкции | ||||
| 
 | ||||
| | Инструкция  | Аргумент       | Описание                                                             | | ||||
| |-------------|----------------|----------------------------------------------------------------------| | ||||
| | PUSH        | `uint16`       | Добавить в стек                                                      | | ||||
| | POP         | -              | Удалить из стека                                                     | | ||||
| | DUP         | -              | Дублировать последнее значение в стеке                               | | ||||
| | SWAP        | -              | Поменять местами последние 2 значения в стеке                        | | ||||
| | ADD         | -              | Прибавление последних 2-х значений из стека                          | | ||||
| | SUB         | -              | Вычитание последних 2-х значений из стека                            | | ||||
| | MUL         | -              | Умножение последних 2-х значений из стека                            | | ||||
| | DIV         | -              | Деление последних 2-х значений из стека                              | | ||||
| | JMP         | `uint16` лейбл | Перейти к лейблу <имя>                                               | | ||||
| | JNZ         | `uint16` лейбл | Перейти к лейблу <имя> если значение с верхушки стека не 0           | | ||||
| | JZ          | `uint16` лейбл | Перейти к лейблу <имя> если значение с верхушки стека 0              | | ||||
| | NOP         | -              | Ничего не делает                                                     | | ||||
| | EXIT        | -              | Выход из программы с кодом 0                                         | | ||||
| | PUTC        | -              | Вывести символ в консоль                                             | | ||||
| | GETC        | -              | Получить символ с консоли, добавить символ в стек                    | | ||||
| | MEOW        | -              | Принт, POP'ает со стека                                              | | ||||
| | DUMP        | -              | Вывести весь стек в консоль, понятное дело не попает со стека        | | ||||
| | SCAN        | -              | Сканирует ввод из консоли на `short`'ы и пушит в стек                | | ||||
| | #EXEC       | arg            | Выполнить код из файла, указанного в аргументе*                      | | ||||
| | ARGS        | `uint16`       | POP'ает аргумент значений с основного стека и пушит их в стек модуля, если указать аргумент 0, то нужное кол-во аргументов она возьмет(попнув) с оригинального стека  | | ||||
| | SIZE        |                | Пушит в стек значение размера стека                                     | | ||||
| | QUIT        | `uint16`       | Полностью завершает выполнение программы. Как аргумент попает exit-код. | | ||||
| 
 | ||||
| > \*путь относительно места вызова интерпретатора. Создает отдельный стек для модуля, но передает основной для того чтобы взять оттуда аргументы. После того как модуль выполнился, пушит весь стек модуля в основной. | ||||
| 
 | ||||
| ## Лейблы | ||||
| 
 | ||||
| Лейблы могут быть только `unsigned short`'ами | ||||
| От 0 (main-лейбл) до минимум 256 | ||||
| Если юзер высрал два лейбла с одинаковыми идентификаторами, то интерпретатор/компилятор должен выдать ошибку | ||||
							
								
								
									
										5
									
								
								build.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								build.bat
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| @echo off | ||||
| cargo build --release | ||||
| cargo zigbuild --release --target x86_64-unknown-linux-gnu | ||||
| copy target\release\labast.exe bin\ /Y | ||||
| copy target\x86_64-unknown-linux-gnu\release\labast bin\ /Y | ||||
							
								
								
									
										9
									
								
								example-scripts/expr.lb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								example-scripts/expr.lb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| ; written by Labashki developer - aeris | ||||
| @ 0 | ||||
|     #EXPR >++:+\ | ||||
|     DUMP | ||||
| 
 | ||||
| ; Expected output | ||||
| ; | ||||
| ; 0: 3 | ||||
| ; 1: 2 | ||||
							
								
								
									
										30
									
								
								example-scripts/hello-world.lb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								example-scripts/hello-world.lb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | ||||
| PUSH 72  ; H | ||||
| PUTC     ; Print to console | ||||
| PUSH 101 ; e | ||||
| PUTC | ||||
| PUSH 108 ; l | ||||
| PUTC | ||||
| PUSH 108 ; l | ||||
| PUTC | ||||
| PUSH 111 ; o | ||||
| PUTC | ||||
| PUSH 32  ; <space> | ||||
| PUTC | ||||
| PUSH 76  ; L | ||||
| PUTC | ||||
| PUSH 97  ; a | ||||
| PUTC | ||||
| PUSH 98  ; b | ||||
| PUTC | ||||
| PUSH 97  ; a | ||||
| PUTC | ||||
| PUSH 115 ; s | ||||
| PUTC | ||||
| PUSH 104 ; h | ||||
| PUTC | ||||
| PUSH 107 ; k | ||||
| PUTC | ||||
| PUSH 105 ; i | ||||
| PUTC | ||||
| PUSH 33  ; ! | ||||
| PUTC | ||||
							
								
								
									
										20
									
								
								example-scripts/labels.lb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								example-scripts/labels.lb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| @ 1 | ||||
|   PUSH 115 ; s | ||||
|   PUTC | ||||
|   PUSH 104 ; h | ||||
|   PUTC | ||||
|   PUSH 107 ; k | ||||
|   PUTC | ||||
|   PUSH 105 ; i | ||||
|   PUTC | ||||
|   EXIT | ||||
| @ 0 | ||||
|   PUSH 76  ; L | ||||
|   PUTC | ||||
|   PUSH 97  ; a | ||||
|   PUTC | ||||
|   PUSH 98  ; b | ||||
|   PUTC | ||||
|   PUSH 97  ; a | ||||
|   PUTC | ||||
|   JMP 1 | ||||
							
								
								
									
										23
									
								
								example-scripts/math.lb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								example-scripts/math.lb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| ; Addition | ||||
| PUSH 2 ; a = 2 | ||||
| PUSH 3 ; b = 2 | ||||
| ADD    ; a + b | ||||
| MEOW   ; = 5 | ||||
| 
 | ||||
| ; Subtraction | ||||
| PUSH 9 ; a = 9 | ||||
| PUSH 4 ; b = 4 | ||||
| SUB    ; b - a | ||||
| MEOW   ; = 5 | ||||
| 
 | ||||
| ; Multiplication | ||||
| PUSH 9 ; a = 9 | ||||
| PUSH 5 ; b = 5 | ||||
| MUL    ; b * a | ||||
| MEOW   ; = 45 | ||||
| 
 | ||||
| ; Division | ||||
| PUSH 81; a = 81 | ||||
| PUSH 9 ; b = 9 | ||||
| DIV    ; b / a | ||||
| MEOW   ; = 9 | ||||
							
								
								
									
										12
									
								
								example-scripts/modules/main.lb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								example-scripts/modules/main.lb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| PUSH 76 ; L | ||||
| PUTC | ||||
| PUSH 97 ; a | ||||
| PUTC | ||||
| PUSH 98 ; b | ||||
| PUTC | ||||
| PUSH 97 ; a | ||||
| PUTC | ||||
| #EXEC second_part.lb | ||||
| PUSH 33 ; ! | ||||
| PUTC | ||||
| QUIT | ||||
							
								
								
									
										8
									
								
								example-scripts/modules/second_part.lb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								example-scripts/modules/second_part.lb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| PUSH 115 ; s | ||||
| PUTC | ||||
| PUSH 104 ; h | ||||
| PUTC | ||||
| PUSH 107 ; k | ||||
| PUTC | ||||
| PUSH 105 ; i | ||||
| PUTC | ||||
							
								
								
									
										15
									
								
								example-scripts/pick.lb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								example-scripts/pick.lb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| ; written by Labashki developer - aeris | ||||
| @ 0 | ||||
|     PUSH 2 | ||||
|     PUSH 3 | ||||
|     PUSH 4 | ||||
|     PUSH 1 | ||||
|     PICK | ||||
|     DUMP | ||||
| 
 | ||||
| ; Expected output | ||||
| ; | ||||
| ; 0: 2 | ||||
| ; 1: 3 | ||||
| ; 2: 4 | ||||
| ; 3: 3 | ||||
							
								
								
									
										10
									
								
								example-scripts/size.lb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								example-scripts/size.lb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| @ 0 | ||||
|     PUSH 1 | ||||
|     PUSH 2 | ||||
|     PUSH 3 | ||||
|     SIZE | ||||
|     MEOW | ||||
| 
 | ||||
| ; Expected output | ||||
| ; | ||||
| ; 3 | ||||
							
								
								
									
										45
									
								
								src/errors.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/errors.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| use std::fmt::Display; | ||||
| 
 | ||||
| pub enum RunError { | ||||
|     RequestArgsInMainModule, | ||||
|     ExecuteItself(String), | ||||
|     FailToReadFile, | ||||
|     FailToGetCharFromConsole, | ||||
|     InvalidInputUShortInt, | ||||
|     PickTooDeep, | ||||
|     PickOutOfBounds, | ||||
|     FailToReadLineFromConsole, | ||||
|     UnknownLabel(u16), | ||||
|     InvalidExpressionUnknownOperator(String), | ||||
|     MemoryEmpty, | ||||
| } | ||||
| 
 | ||||
| impl Display for RunError { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         match self { | ||||
|             RunError::RequestArgsInMainModule => write!(f, "Can't require arguments in the main module"), | ||||
|             RunError::ExecuteItself(mod_name) => write!(f, "Module {}: Can't execute itself", mod_name), | ||||
|             RunError::FailToReadFile => write!(f, "Unable to read file"), | ||||
|             RunError::FailToGetCharFromConsole => write!(f, "Failed to get character from console"), | ||||
|             RunError::InvalidInputUShortInt => write!(f, "Invalid input. Please enter a valid unsigned short integer"), | ||||
|             RunError::PickTooDeep => write!(f, "Picking too deep"), | ||||
|             RunError::PickOutOfBounds => write!(f, "Trying to get a value out of bounds"), | ||||
|             RunError::FailToReadLineFromConsole => write!(f, "Failed to read line from console"), | ||||
|             RunError::UnknownLabel(label_name) => write!(f, "Unknown label: {}", label_name), | ||||
|             RunError::InvalidExpressionUnknownOperator(name) => write!(f, "Invalid expression: unknown operator '{}'", name), | ||||
|             RunError::MemoryEmpty => write!(f, "No elements in memory!"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub enum ParseError { | ||||
|     DataNotAUInt(String, usize) | ||||
| } | ||||
| 
 | ||||
| impl Display for ParseError { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         match self { | ||||
|             ParseError::DataNotAUInt(name, line) => write!(f, "Argument for {0} at {1} isn't a number", name, line), | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										86
									
								
								src/execute.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								src/execute.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,86 @@ | ||||
| use crate::{instructions, stack::Stack}; | ||||
| 
 | ||||
| fn find_labels(stack: &mut Stack) { | ||||
|     while stack.program_counter < (stack.program.len() as u16) { | ||||
|         let label = &stack.program[stack.program_counter as usize]; | ||||
|         stack.program_counter += 1; | ||||
|         
 | ||||
|         if !label.name.starts_with('@') { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         if stack.labels[label.data as usize].is_some() { | ||||
|             eprintln!("Label {} already defined", label.data); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if label.data == 0 { | ||||
|             stack.labels[0] = Some(stack.program_counter as i16); | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         stack.labels[label.data as usize] = Some(stack.program_counter as i16); | ||||
|     } | ||||
| 
 | ||||
|     if stack.labels[0].is_some() { | ||||
|         stack.program_counter = stack.labels[0].unwrap() as u16; | ||||
|     } else { | ||||
|         stack.program_counter = 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn execute(stack: &mut Stack, mut origin_stack: Option<&mut Stack>, mod_name: &String) { | ||||
|     find_labels(stack); | ||||
| 
 | ||||
|     while let Some(instruction) = stack.program.get(stack.program_counter as usize) { | ||||
|         stack.program_counter += 1; | ||||
|         
 | ||||
|         if instruction.name.starts_with('@') { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         match instruction.name.as_str() { | ||||
|             // Stack operations
 | ||||
|             "PUSH" => instructions::push::push(&mut stack.memory, &instruction.data), | ||||
|             "PICK" => instructions::pick::pick(&mut stack.memory, &instruction.data), | ||||
|             "POP"  => instructions::pop::pop(&mut stack.memory), | ||||
|             "DUP"  => instructions::dup::dup(&mut stack.memory), | ||||
|             "SWAP" => instructions::swap::swap(&mut stack.memory), | ||||
|             "MEOW" => instructions::meow::meow(&mut stack.memory), | ||||
|             "DUMP" => instructions::dump::dump(&mut stack.memory), | ||||
|             "SIZE" => instructions::size::size(&mut stack.memory), | ||||
| 
 | ||||
|             "#EXPR" => instructions::expr::expr(&mut stack.memory, &instruction.arg), | ||||
| 
 | ||||
|             // Labels
 | ||||
|             "JMP" => instructions::jmp::jmp(&mut stack.labels, &mut stack.program_counter, &instruction.data), | ||||
|             "JNZ" => instructions::jnz::jnz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, &instruction.data), | ||||
|             "JZ"  => instructions::jz::jz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, &instruction.data), | ||||
| 
 | ||||
|             // Math operations
 | ||||
|             "ADD" => instructions::add::add(&mut stack.memory), | ||||
|             "SUB" => instructions::sub::sub(&mut stack.memory), | ||||
|             "MUL" => instructions::mul::mul(&mut stack.memory), | ||||
|             "DIV" => instructions::div::div(&mut stack.memory), | ||||
| 
 | ||||
|             // Console operations
 | ||||
|             "PUTC" => instructions::putc::putc(&mut stack.memory), | ||||
|             "GETC" => instructions::getc::getc(&mut stack.memory), | ||||
|             "SCAN" => instructions::scan::scan(&mut stack.memory), | ||||
| 
 | ||||
|             // Modules
 | ||||
|             "ARGS"  => instructions::args::args(&mut stack.memory, &mut origin_stack, &instruction.data), | ||||
|             "#EXEC" => instructions::exec::exec(stack, &instruction.arg.clone(), &mod_name), | ||||
| 
 | ||||
|             // ?
 | ||||
|             "NOP"  => continue, | ||||
|             "EXIT" => instructions::exit::exit(&instruction.data), | ||||
|             "QUIT" => std::process::exit(0), | ||||
| 
 | ||||
|             _ => { | ||||
|                 eprintln!("Unknown instruction: {}", instruction.name); | ||||
|                 std::process::exit(2); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										8
									
								
								src/instructions/add.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/instructions/add.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| use crate::errors::RunError; | ||||
| 
 | ||||
| pub fn add(memory: &mut Vec<u16>) { | ||||
|     let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); | ||||
|     let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); | ||||
| 
 | ||||
|     memory.push(a + b); | ||||
| } | ||||
							
								
								
									
										21
									
								
								src/instructions/args.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/instructions/args.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| use crate::{errors::RunError, stack::Stack}; | ||||
| 
 | ||||
| pub fn args(memory: &mut Vec<u16>, origin_stack: &mut Option<&mut Stack>, data: &u16) { | ||||
|     let origin_memory = &mut origin_stack.as_mut().expect("msg").memory; | ||||
| 
 | ||||
|     if *origin_memory == *memory { | ||||
|         eprintln!("{}", RunError::RequestArgsInMainModule); | ||||
|         std::process::exit(2); | ||||
|     } | ||||
| 
 | ||||
|     let quanity: u16; | ||||
|     if *data == 0 { | ||||
|         quanity = origin_memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); | ||||
|     } else { | ||||
|         quanity = *data; | ||||
|     } | ||||
| 
 | ||||
|     for _ in 0..quanity { | ||||
|         memory.push(origin_memory.pop().expect(&format!("{}", RunError::MemoryEmpty))); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										8
									
								
								src/instructions/div.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/instructions/div.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| use crate::errors::RunError; | ||||
| 
 | ||||
| pub fn div(memory: &mut Vec<u16>) { | ||||
|     let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); | ||||
|     let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); | ||||
| 
 | ||||
|     memory.push(b / a); | ||||
| } | ||||
							
								
								
									
										5
									
								
								src/instructions/dump.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/instructions/dump.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| pub fn dump(memory: &mut Vec<u16>) { | ||||
|     for (i, entry) in memory.iter().enumerate() { | ||||
|         println!("{0}: {1}", i, entry); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										5
									
								
								src/instructions/dup.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/instructions/dup.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| use crate::errors::RunError; | ||||
| 
 | ||||
| pub fn dup(memory: &mut Vec<u16>) { | ||||
|     memory.push(*memory.last().expect(&format!("{}", RunError::MemoryEmpty))); | ||||
| } | ||||
							
								
								
									
										20
									
								
								src/instructions/exec.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/instructions/exec.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| use std::fs; | ||||
| use crate::{parse, execute, Stack, errors::RunError}; | ||||
| 
 | ||||
| pub fn exec(mut stack: &mut Stack, arg: &String, mod_name: &String) { | ||||
|     if mod_name == arg { | ||||
|         eprintln!("{}", RunError::ExecuteItself(arg.to_string())); | ||||
|         std::process::exit(2); | ||||
|     } | ||||
| 
 | ||||
|     let lines = fs::read_to_string(&arg).expect(&format!("{}", RunError::FailToReadFile)); | ||||
|     let mut temp_stack = Stack::new(); | ||||
| 
 | ||||
|     parse(&mut temp_stack, &lines); | ||||
| 
 | ||||
|     execute(&mut temp_stack, Some(&mut stack), &arg.clone()); | ||||
| 
 | ||||
|     for item in temp_stack.memory { | ||||
|         stack.memory.push(item); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										3
									
								
								src/instructions/exit.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/instructions/exit.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| pub fn exit(data: &u16) { | ||||
|     std::process::exit((*data).into()); | ||||
| } | ||||
							
								
								
									
										31
									
								
								src/instructions/expr.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/instructions/expr.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| use crate::errors::RunError; | ||||
| 
 | ||||
| pub fn expr(memory: &mut Vec<u16>, arg: &String) { | ||||
|     for code in arg.chars() { | ||||
|         match code { | ||||
|             '>' => memory.push(0), | ||||
|             '$' => { memory.pop(); }, | ||||
|             ':' => memory.push(*memory.last().expect(&format!("{}", RunError::MemoryEmpty))), | ||||
|             '\\' => { | ||||
|                 let ax = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); | ||||
|                 let ax2 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); | ||||
|                 
 | ||||
|                 memory.push(ax); | ||||
|                 memory.push(ax2); | ||||
|             } | ||||
|             '+' => { | ||||
|                 let ax = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); | ||||
|                 memory.push(ax + 1); | ||||
|             } | ||||
|             '-' => { | ||||
|                 let ax = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); | ||||
|                 memory.push(ax - 1); | ||||
|             } | ||||
| 
 | ||||
|             _ => { | ||||
|                 eprintln!("{}", RunError::InvalidExpressionUnknownOperator(code.to_string())); | ||||
|                 std::process::exit(2); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										13
									
								
								src/instructions/getc.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/instructions/getc.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| use std::io::Read; | ||||
| use crate::errors::RunError; | ||||
| 
 | ||||
| pub fn getc(memory: &mut Vec<u16>) { | ||||
|     let char = std::io::stdin() | ||||
|         .bytes() | ||||
|         .next() | ||||
|         .and_then(|result| result.ok()) | ||||
|         .map(|byte| byte as u16) | ||||
|         .expect(&format!("{}", RunError::FailToGetCharFromConsole)); | ||||
|     
 | ||||
|     memory.push(char); | ||||
| } | ||||
							
								
								
									
										10
									
								
								src/instructions/jmp.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/instructions/jmp.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| use crate::errors::RunError; | ||||
| 
 | ||||
| pub fn jmp(labels: &mut [Option<i16>; 256], program_counter: &mut u16, data: &u16) { | ||||
|     if labels[*data as usize].is_none() { | ||||
|         eprintln!("{}", RunError::UnknownLabel(*data)); | ||||
|         std::process::exit(2); | ||||
|     } | ||||
| 
 | ||||
|     *program_counter = (labels[*data as usize].unwrap() - 1) as u16; | ||||
| } | ||||
							
								
								
									
										12
									
								
								src/instructions/jnz.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/instructions/jnz.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| use crate::errors::RunError; | ||||
| 
 | ||||
| pub fn jnz(memory: &mut Vec<u16>, labels: &mut [Option<i16>; 256], program_counter: &mut u16, data: &u16) { | ||||
|     if labels[*data as usize].is_none() { | ||||
|         eprintln!("{}", RunError::UnknownLabel(*data)); | ||||
|         std::process::exit(2); | ||||
|     } | ||||
| 
 | ||||
|     if memory.pop() != Some(0) { | ||||
|         *program_counter = (labels[*data as usize].unwrap() - 1) as u16; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										12
									
								
								src/instructions/jz.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/instructions/jz.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| use crate::errors::RunError; | ||||
| 
 | ||||
| pub fn jz(memory: &mut Vec<u16>, labels: &mut [Option<i16>; 256], program_counter: &mut u16, data: &u16) { | ||||
|     if labels[*data as usize].is_none() { | ||||
|         eprintln!("{}", RunError::UnknownLabel(*data)); | ||||
|         std::process::exit(2); | ||||
|     } | ||||
| 
 | ||||
|     if memory.pop() == Some(0) { | ||||
|         *program_counter = (labels[*data as usize].unwrap() - 1) as u16; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										5
									
								
								src/instructions/meow.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/instructions/meow.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| use crate::errors::RunError; | ||||
| 
 | ||||
| pub fn meow(memory: &mut Vec<u16>) { | ||||
|     println!("{}", memory.pop().expect(&format!("{}", RunError::MemoryEmpty))); | ||||
| } | ||||
							
								
								
									
										22
									
								
								src/instructions/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/instructions/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| pub mod push; | ||||
| pub mod pop; | ||||
| pub mod dup; | ||||
| pub mod swap; | ||||
| pub mod add; | ||||
| pub mod sub; | ||||
| pub mod mul; | ||||
| pub mod div; | ||||
| pub mod jmp; | ||||
| pub mod jnz; | ||||
| pub mod jz; | ||||
| pub mod pick; | ||||
| pub mod putc; | ||||
| pub mod getc; | ||||
| pub mod meow; | ||||
| pub mod dump; | ||||
| pub mod scan; | ||||
| pub mod exec; | ||||
| pub mod args; | ||||
| pub mod expr; | ||||
| pub mod size; | ||||
| pub mod exit; | ||||
							
								
								
									
										8
									
								
								src/instructions/mul.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/instructions/mul.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| use crate::errors::RunError; | ||||
| 
 | ||||
| pub fn mul(memory: &mut Vec<u16>) { | ||||
|     let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); | ||||
|     let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); | ||||
| 
 | ||||
|     memory.push(b * a); | ||||
| } | ||||
							
								
								
									
										11
									
								
								src/instructions/pick.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/instructions/pick.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| use crate::errors::RunError; | ||||
| 
 | ||||
| pub fn pick(memory: &mut Vec<u16>, data: &u16) { | ||||
|     if *data > memory.len() as u16 { | ||||
|         eprintln!("{}", RunError::PickTooDeep); | ||||
|         std::process::exit(2); | ||||
|     } | ||||
| 
 | ||||
|     let arg = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); | ||||
|     memory.push(*memory.get(memory.len() - (arg as usize) - 1).expect(&format!("{}", RunError::PickOutOfBounds))); | ||||
| } | ||||
							
								
								
									
										3
									
								
								src/instructions/pop.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/instructions/pop.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| pub fn pop(memory: &mut Vec<u16>) { | ||||
|     memory.pop(); | ||||
| } | ||||
							
								
								
									
										3
									
								
								src/instructions/push.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/instructions/push.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| pub fn push(memory: &mut Vec<u16>, data: &u16) { | ||||
|     memory.push(*data); | ||||
| } | ||||
							
								
								
									
										5
									
								
								src/instructions/putc.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/instructions/putc.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| use crate::errors::RunError; | ||||
| 
 | ||||
| pub fn putc(memory: &mut Vec<u16>) { | ||||
|     print!("{}", memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) as u8 as char); | ||||
| } | ||||
							
								
								
									
										10
									
								
								src/instructions/scan.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/instructions/scan.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| use crate::errors::RunError; | ||||
| 
 | ||||
| pub fn scan(memory: &mut Vec<u16>) { | ||||
|     let mut input = String::new(); | ||||
| 
 | ||||
|     std::io::stdin().read_line(&mut input).expect(&format!("{}", RunError::FailToReadLineFromConsole)); | ||||
|                 
 | ||||
|     let num = input.trim().parse().expect(&format!("{}", RunError::InvalidInputUShortInt)); | ||||
|     memory.push(num); | ||||
| } | ||||
							
								
								
									
										3
									
								
								src/instructions/size.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/instructions/size.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| pub fn size(memory: &mut Vec<u16>) { | ||||
|     memory.push(memory.len() as u16); | ||||
| } | ||||
							
								
								
									
										8
									
								
								src/instructions/sub.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/instructions/sub.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| use crate::errors::RunError; | ||||
| 
 | ||||
| pub fn sub(memory: &mut Vec<u16>) { | ||||
|     let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); | ||||
|     let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); | ||||
| 
 | ||||
|     memory.push(b - a); | ||||
| } | ||||
							
								
								
									
										9
									
								
								src/instructions/swap.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/instructions/swap.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| use crate::errors::RunError; | ||||
| 
 | ||||
| pub fn swap(memory: &mut Vec<u16>) { | ||||
|     let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); | ||||
|     let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); | ||||
| 
 | ||||
|     memory.push(a); | ||||
|     memory.push(b); | ||||
| } | ||||
							
								
								
									
										27
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| use std::{env, fs}; | ||||
| use errors::RunError; | ||||
| use execute::execute; | ||||
| use parse::parse; | ||||
| use stack::Stack; | ||||
| 
 | ||||
| mod stack; | ||||
| mod parse; | ||||
| mod execute; | ||||
| mod instructions; | ||||
| mod errors; | ||||
| 
 | ||||
| fn main() { | ||||
|     let args: Vec<String> = env::args().collect(); | ||||
|     
 | ||||
|     if args.len() < 2 { | ||||
|         eprintln!("Usage: {0} [FILE]", args[0]); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     let mut stack = Stack::new(); | ||||
|     let lines = fs::read_to_string(&args[1]).expect(&format!("{}", RunError::FailToReadFile)); | ||||
| 
 | ||||
|     parse(&mut stack, &lines); | ||||
| 
 | ||||
|     execute(&mut stack, None, &args[1]); | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/parse.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/parse.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| use crate::{errors::ParseError, stack::{Instruction, Stack}}; | ||||
| 
 | ||||
| pub fn parse(stack: &mut Stack, file_content: &str) { | ||||
|     for (i, line) in file_content.lines().enumerate() { | ||||
|         if line.trim().starts_with(';') || line.is_empty() { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         let inst_line: String; | ||||
|         if let Some(comment_index) = line.trim().find(';') { | ||||
|             inst_line = line.trim().chars().take(comment_index).collect(); | ||||
|         } else { | ||||
|             inst_line = line.trim().chars().collect(); | ||||
|         } | ||||
| 
 | ||||
|         let command: Vec<String> = inst_line.split_whitespace().map(String::from).collect(); | ||||
| 
 | ||||
|         let name: String; | ||||
|         let mut arg: String = String::new(); | ||||
|         let mut data: u16 = 0; | ||||
| 
 | ||||
|         name = command[0].clone(); | ||||
| 
 | ||||
|         if command.len() >= 2 { | ||||
|             match name.chars().nth(0) { | ||||
|                 Some('#') => arg = command[1].to_string(), | ||||
|                 _ => data = command[1].parse().expect(&format!("{}", ParseError::DataNotAUInt(command[0].to_string(), i + 1))), | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let inst = Instruction { name, arg, data }; | ||||
|         stack.program.push(inst); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										25
									
								
								src/stack.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/stack.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct Instruction { | ||||
|     pub name: String, | ||||
|     pub arg: String, | ||||
|     pub data: u16 | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct Stack { | ||||
|     pub program: Vec<Instruction>, | ||||
|     pub program_counter: u16, | ||||
|     pub labels: [Option<i16>; 256], | ||||
|     pub memory: Vec<u16> | ||||
| } | ||||
| 
 | ||||
| impl Stack { | ||||
|     pub fn new() -> Stack { | ||||
|         return Stack { | ||||
|             program: Vec::new(), | ||||
|             program_counter: 0, | ||||
|             labels: [None; 256], | ||||
|             memory: Vec::new() | ||||
|         }; | ||||
|     } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user