Skip to content

Commit 95b2f6e

Browse files
authored
fix: remove duplicates from symbol table, forbid var redeclarations (#21)
**Description** This PR modifies the symbol table creation logic by: - Storing the table as a global variable in the form of a Vec, every time we parse a symbol we push it to this vector - If compilation is successful or we exit with an error we first dump the table into a file - When parsing the variable declarations inside `init {}` if we find a symbol that is already in the table we exit with an error. This PR also modifies the parsing of negative floats and integers: - The enum variants `NumberNegativeInt` and `NumberNegativeInt` were removed in favor of using i64 and f32 to store negatives.
1 parent eebfe40 commit 95b2f6e

File tree

9 files changed

+266
-172
lines changed

9 files changed

+266
-172
lines changed

inputs/test.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@ init {
66
#+ Ejemplo de una variable mal declarada +#
77
#+ fecha : date +#
88
#+ h : foat +#
9+
10+
#+ Ejemplo de error por redeclaracion de variable +#
11+
#+ a1: int +#
912
}
1013

1114
a1 := -125
15+
b2 := -125
1216
b2 := a1
1317

1418
c33 := 5.34

src/context.rs

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
use std::{
22
cell::RefCell,
3+
fmt::Display,
34
fs::{File, OpenOptions, read_to_string},
45
io::{self, Read, Seek, Write},
6+
ops::Range,
57
path::PathBuf,
68
};
79
use thiserror::Error;
810

11+
use crate::{
12+
grammar_actions::{DataType, TokenFloatLiteral, TokenIntLiteral, TokenStringLiteral},
13+
grammar_lexer::log_error,
14+
};
15+
916
#[derive(Debug, Error)]
1017
pub enum CompilerError {
1118
#[error("Parser internal error: {0:?}")]
@@ -25,6 +32,7 @@ thread_local! {
2532
pub static LEXER_FILE: RefCell<Option<File>> = const { RefCell::new(None) };
2633
pub static PARSER_FILE: RefCell<Option<File>> = const { RefCell::new(None) };
2734
pub static SYMBOL_TABLE_FILE: RefCell<Option<File>> = const { RefCell::new(None) };
35+
pub static SYMBOL_TABLE: RefCell<Vec<SymbolTableElement>> = const { RefCell::new(Vec::new())}
2836
}
2937

3038
pub fn set_source_file_path(path: PathBuf) {
@@ -95,15 +103,34 @@ pub fn open_symbol_table_file() -> Result<(), io::Error> {
95103
})
96104
}
97105

98-
pub fn write_to_symbol_table_file(line: &str) -> Result<(), io::Error> {
106+
pub fn dump_symbol_table_to_file() -> Result<(), io::Error> {
99107
SYMBOL_TABLE_FILE.with(|f| {
100108
if let Some(mut file) = f.borrow_mut().as_ref() {
101-
writeln!(file, "{line}")?;
109+
for symbol in SYMBOL_TABLE.take() {
110+
writeln!(file, "{symbol}")?;
111+
}
102112
}
103113
Ok(())
104114
})
105115
}
106116

117+
pub fn log_error_and_exit(
118+
pos: Range<usize>,
119+
error: CompilerError,
120+
offset: usize,
121+
trace: bool,
122+
) -> ! {
123+
dump_symbol_table_to_file().expect("Failed to write symbol table");
124+
log_error(
125+
pos,
126+
error,
127+
offset,
128+
&read_source_to_string().expect("Failed to print error location"),
129+
trace,
130+
);
131+
std::process::exit(1)
132+
}
133+
107134
pub fn read_source_to_string() -> Result<String, CompilerError> {
108135
SOURCE_CODE_PATH.with(|f| {
109136
if let Some(path) = f.borrow().as_ref() {
@@ -134,3 +161,79 @@ pub fn read_parser_file_to_string() -> Result<String, CompilerError> {
134161
}
135162
})
136163
}
164+
165+
#[derive(Clone, Debug)]
166+
pub enum SymbolTableElement {
167+
VarDeclaration(String, DataType, usize),
168+
IntLiteral(TokenIntLiteral),
169+
FloatLiteral(TokenFloatLiteral),
170+
StringLiteral(TokenStringLiteral),
171+
}
172+
173+
impl Display for SymbolTableElement {
174+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175+
match self {
176+
Self::FloatLiteral(float) => write!(
177+
f,
178+
"{}|CONST_FLOAT|{}|{}",
179+
float.original,
180+
float.original,
181+
float.original.len()
182+
)?,
183+
Self::IntLiteral(int) => {
184+
write!(f, "{}|CONST_INT|{}|{}", int, int, int.to_string().len())?
185+
}
186+
Self::StringLiteral(string) => {
187+
write!(f, "{}|CONST_STRING|{}|{}", string, string, string.len())?
188+
}
189+
Self::VarDeclaration(token, r#type, length) => {
190+
write!(f, "{}|{}|-|{}", token, r#type, length)?
191+
}
192+
};
193+
Ok(())
194+
}
195+
}
196+
197+
impl PartialEq for SymbolTableElement {
198+
fn eq(&self, other: &Self) -> bool {
199+
match (self, other) {
200+
(Self::FloatLiteral(token0), Self::FloatLiteral(token1)) => token0 == token1,
201+
(Self::IntLiteral(token0), Self::IntLiteral(token1)) => token0 == token1,
202+
(Self::StringLiteral(token0), Self::StringLiteral(token1)) => token0 == token1,
203+
(Self::VarDeclaration(token0, _, _), Self::VarDeclaration(token1, _, _)) => {
204+
token0 == token1
205+
}
206+
_ => false,
207+
}
208+
}
209+
}
210+
211+
impl From<TokenIntLiteral> for SymbolTableElement {
212+
fn from(value: TokenIntLiteral) -> Self {
213+
Self::IntLiteral(value)
214+
}
215+
}
216+
217+
impl From<TokenFloatLiteral> for SymbolTableElement {
218+
fn from(value: TokenFloatLiteral) -> Self {
219+
Self::FloatLiteral(value)
220+
}
221+
}
222+
223+
impl From<TokenStringLiteral> for SymbolTableElement {
224+
fn from(value: TokenStringLiteral) -> Self {
225+
Self::StringLiteral(value)
226+
}
227+
}
228+
pub fn push_to_symbol_table(item: SymbolTableElement) {
229+
SYMBOL_TABLE.with(|table| {
230+
// Avoid pushing duplicate symbols to the symbol table
231+
if !symbol_exists(&item) {
232+
table.borrow_mut().push(item);
233+
}
234+
})
235+
}
236+
237+
pub fn symbol_exists(item: &SymbolTableElement) -> bool {
238+
SYMBOL_TABLE.with(|table| table.borrow().contains(item))
239+
}

0 commit comments

Comments
 (0)