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