Analyzer -> SymbolTable
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
use std::{collections::HashMap, fmt::Write};
|
use std::{collections::HashMap, fmt::Write};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
analyzer::Analyzer,
|
|
||||||
parser::{Expr, Stmt},
|
parser::{Expr, Stmt},
|
||||||
|
symbol_table::SymbolTable,
|
||||||
tokenizer::{Token, TokenType, ZernError, error},
|
tokenizer::{Token, TokenType, ZernError, error},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -74,17 +74,17 @@ pub struct CodegenX86_64<'a> {
|
|||||||
data_section: String,
|
data_section: String,
|
||||||
label_counter: usize,
|
label_counter: usize,
|
||||||
data_counter: usize,
|
data_counter: usize,
|
||||||
pub analyzer: &'a Analyzer,
|
pub symbol_table: &'a SymbolTable,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CodegenX86_64<'a> {
|
impl<'a> CodegenX86_64<'a> {
|
||||||
pub fn new(analyzer: &'a Analyzer) -> CodegenX86_64<'a> {
|
pub fn new(symbol_table: &'a SymbolTable) -> CodegenX86_64<'a> {
|
||||||
CodegenX86_64 {
|
CodegenX86_64 {
|
||||||
output: String::new(),
|
output: String::new(),
|
||||||
data_section: String::new(),
|
data_section: String::new(),
|
||||||
label_counter: 0,
|
label_counter: 0,
|
||||||
data_counter: 1,
|
data_counter: 1,
|
||||||
analyzer,
|
symbol_table,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@ _builtin_environ:
|
|||||||
var_type,
|
var_type,
|
||||||
initializer,
|
initializer,
|
||||||
} => {
|
} => {
|
||||||
// TODO: move to analyzer
|
// TODO: move to typechecker?
|
||||||
if env.get_var(&name.lexeme).is_some() {
|
if env.get_var(&name.lexeme).is_some() {
|
||||||
return error!(
|
return error!(
|
||||||
name.loc,
|
name.loc,
|
||||||
@@ -250,7 +250,7 @@ _builtin_environ:
|
|||||||
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
|
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
|
||||||
}
|
}
|
||||||
Stmt::Const { name: _, value: _ } => {
|
Stmt::Const { name: _, value: _ } => {
|
||||||
// handled in the analyzer
|
// handled in SymbolTable
|
||||||
}
|
}
|
||||||
Stmt::Block(statements) => {
|
Stmt::Block(statements) => {
|
||||||
env.push_scope();
|
env.push_scope();
|
||||||
@@ -398,7 +398,7 @@ _builtin_environ:
|
|||||||
emit!(&mut self.output, "extern {}", name.lexeme);
|
emit!(&mut self.output, "extern {}", name.lexeme);
|
||||||
}
|
}
|
||||||
Stmt::Struct { name: _, fields: _ } => {
|
Stmt::Struct { name: _, fields: _ } => {
|
||||||
// handled in the analyzer
|
// handled in SymbolTable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -555,11 +555,11 @@ _builtin_environ:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Variable(name) => {
|
Expr::Variable(name) => {
|
||||||
if self.analyzer.constants.contains_key(&name.lexeme) {
|
if self.symbol_table.constants.contains_key(&name.lexeme) {
|
||||||
emit!(
|
emit!(
|
||||||
&mut self.output,
|
&mut self.output,
|
||||||
" mov rax, {}",
|
" mov rax, {}",
|
||||||
self.analyzer.constants[&name.lexeme]
|
self.symbol_table.constants[&name.lexeme]
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let var = match env.get_var(&name.lexeme) {
|
let var = match env.get_var(&name.lexeme) {
|
||||||
@@ -655,7 +655,11 @@ _builtin_environ:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Expr::Variable(callee_name) = &**callee {
|
if let Expr::Variable(callee_name) = &**callee {
|
||||||
if self.analyzer.functions.contains_key(&callee_name.lexeme) {
|
if self
|
||||||
|
.symbol_table
|
||||||
|
.functions
|
||||||
|
.contains_key(&callee_name.lexeme)
|
||||||
|
{
|
||||||
// its a function (defined/builtin/extern)
|
// its a function (defined/builtin/extern)
|
||||||
emit!(&mut self.output, " call {}", callee_name.lexeme);
|
emit!(&mut self.output, " call {}", callee_name.lexeme);
|
||||||
} else {
|
} else {
|
||||||
@@ -702,7 +706,7 @@ _builtin_environ:
|
|||||||
}
|
}
|
||||||
Expr::AddrOf { op, expr } => match *expr.clone() {
|
Expr::AddrOf { op, expr } => match *expr.clone() {
|
||||||
Expr::Variable(name) => {
|
Expr::Variable(name) => {
|
||||||
if self.analyzer.functions.contains_key(&name.lexeme) {
|
if self.symbol_table.functions.contains_key(&name.lexeme) {
|
||||||
emit!(&mut self.output, " mov rax, {}", name.lexeme);
|
emit!(&mut self.output, " mov rax, {}", name.lexeme);
|
||||||
} else {
|
} else {
|
||||||
let var = match env.get_var(&name.lexeme) {
|
let var = match env.get_var(&name.lexeme) {
|
||||||
@@ -726,7 +730,7 @@ _builtin_environ:
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Expr::New(struct_name) => {
|
Expr::New(struct_name) => {
|
||||||
let struct_fields = &self.analyzer.structs[&struct_name.lexeme];
|
let struct_fields = &self.symbol_table.structs[&struct_name.lexeme];
|
||||||
|
|
||||||
// TODO: panic on mem.alloc error
|
// TODO: panic on mem.alloc error
|
||||||
let memory_size = struct_fields.len() * 8;
|
let memory_size = struct_fields.len() * 8;
|
||||||
@@ -771,7 +775,7 @@ _builtin_environ:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let fields = match self.analyzer.structs.get(&struct_name) {
|
let fields = match self.symbol_table.structs.get(&struct_name) {
|
||||||
Some(f) => f,
|
Some(f) => f,
|
||||||
None => {
|
None => {
|
||||||
return error!(&field.loc, format!("unknown struct type: {}", struct_name));
|
return error!(&field.loc, format!("unknown struct type: {}", struct_name));
|
||||||
|
|||||||
10
src/main.rs
10
src/main.rs
@@ -1,6 +1,6 @@
|
|||||||
mod analyzer;
|
|
||||||
mod codegen_x86_64;
|
mod codegen_x86_64;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
mod symbol_table;
|
||||||
mod tokenizer;
|
mod tokenizer;
|
||||||
mod typechecker;
|
mod typechecker;
|
||||||
|
|
||||||
@@ -44,17 +44,17 @@ fn compile_file(args: Args) -> Result<(), ZernError> {
|
|||||||
let parser = parser::Parser::new(tokenizer.tokenize()?);
|
let parser = parser::Parser::new(tokenizer.tokenize()?);
|
||||||
statements.extend(parser.parse()?);
|
statements.extend(parser.parse()?);
|
||||||
|
|
||||||
let mut analyzer = analyzer::Analyzer::new();
|
let mut symbol_table = symbol_table::SymbolTable::new();
|
||||||
for stmt in &statements {
|
for stmt in &statements {
|
||||||
analyzer.register_declaration(stmt)?;
|
symbol_table.register_declaration(stmt)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut typechecker = typechecker::TypeChecker::new(&analyzer);
|
let mut typechecker = typechecker::TypeChecker::new(&symbol_table);
|
||||||
for stmt in &statements {
|
for stmt in &statements {
|
||||||
typechecker.typecheck_stmt(&mut typechecker::Env::new(), stmt)?;
|
typechecker.typecheck_stmt(&mut typechecker::Env::new(), stmt)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut codegen = codegen_x86_64::CodegenX86_64::new(&analyzer);
|
let mut codegen = codegen_x86_64::CodegenX86_64::new(&symbol_table);
|
||||||
codegen.emit_prologue(args.use_gcc)?;
|
codegen.emit_prologue(args.use_gcc)?;
|
||||||
for stmt in statements {
|
for stmt in statements {
|
||||||
codegen.compile_stmt(&mut codegen_x86_64::Env::new(), &stmt)?;
|
codegen.compile_stmt(&mut codegen_x86_64::Env::new(), &stmt)?;
|
||||||
|
|||||||
@@ -34,15 +34,15 @@ impl FnType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Analyzer {
|
pub struct SymbolTable {
|
||||||
pub functions: HashMap<String, FnType>,
|
pub functions: HashMap<String, FnType>,
|
||||||
pub constants: HashMap<String, u64>,
|
pub constants: HashMap<String, u64>,
|
||||||
pub structs: HashMap<String, HashMap<String, StructField>>,
|
pub structs: HashMap<String, HashMap<String, StructField>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Analyzer {
|
impl SymbolTable {
|
||||||
pub fn new() -> Analyzer {
|
pub fn new() -> SymbolTable {
|
||||||
Analyzer {
|
SymbolTable {
|
||||||
functions: HashMap::from([
|
functions: HashMap::from([
|
||||||
("_builtin_heap_head".into(), FnType::new("ptr", vec![])),
|
("_builtin_heap_head".into(), FnType::new("ptr", vec![])),
|
||||||
("_builtin_heap_tail".into(), FnType::new("ptr", vec![])),
|
("_builtin_heap_tail".into(), FnType::new("ptr", vec![])),
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
analyzer::{Analyzer, Type},
|
|
||||||
parser::{Expr, Stmt},
|
parser::{Expr, Stmt},
|
||||||
|
symbol_table::{SymbolTable, Type},
|
||||||
tokenizer::{TokenType, ZernError, error},
|
tokenizer::{TokenType, ZernError, error},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -70,14 +70,14 @@ impl Env {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct TypeChecker<'a> {
|
pub struct TypeChecker<'a> {
|
||||||
analyzer: &'a Analyzer,
|
symbol_table: &'a SymbolTable,
|
||||||
current_function_return_type: String,
|
current_function_return_type: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TypeChecker<'a> {
|
impl<'a> TypeChecker<'a> {
|
||||||
pub fn new(analyzer: &'a Analyzer) -> TypeChecker<'a> {
|
pub fn new(symbol_table: &'a SymbolTable) -> TypeChecker<'a> {
|
||||||
TypeChecker {
|
TypeChecker {
|
||||||
analyzer,
|
symbol_table,
|
||||||
current_function_return_type: String::new(),
|
current_function_return_type: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,7 +110,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
env.define_var(name.lexeme.clone(), actual_type);
|
env.define_var(name.lexeme.clone(), actual_type);
|
||||||
}
|
}
|
||||||
Stmt::Const { name: _, value: _ } => {
|
Stmt::Const { name: _, value: _ } => {
|
||||||
// handled in the analyzer
|
// handled in SymbolTable
|
||||||
}
|
}
|
||||||
Stmt::Block(stmts) => {
|
Stmt::Block(stmts) => {
|
||||||
env.push_scope();
|
env.push_scope();
|
||||||
@@ -207,7 +207,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
Stmt::Break => {}
|
Stmt::Break => {}
|
||||||
Stmt::Continue => {}
|
Stmt::Continue => {}
|
||||||
Stmt::Extern(_) => {
|
Stmt::Extern(_) => {
|
||||||
// handled in the analyzer
|
// handled in the SymbolTable
|
||||||
}
|
}
|
||||||
Stmt::Struct { name: _, fields } => {
|
Stmt::Struct { name: _, fields } => {
|
||||||
for field in fields {
|
for field in fields {
|
||||||
@@ -304,7 +304,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Variable(name) => {
|
Expr::Variable(name) => {
|
||||||
if self.analyzer.constants.contains_key(&name.lexeme) {
|
if self.symbol_table.constants.contains_key(&name.lexeme) {
|
||||||
Ok("i64".into())
|
Ok("i64".into())
|
||||||
} else {
|
} else {
|
||||||
match env.get_var_type(&name.lexeme) {
|
match env.get_var_type(&name.lexeme) {
|
||||||
@@ -341,7 +341,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
Expr::MemberAccess { left, field } => {
|
Expr::MemberAccess { left, field } => {
|
||||||
let left_type = self.typecheck_expr(env, left)?;
|
let left_type = self.typecheck_expr(env, left)?;
|
||||||
|
|
||||||
let fields = match self.analyzer.structs.get(&left_type) {
|
let fields = match self.symbol_table.structs.get(&left_type) {
|
||||||
Some(f) => f,
|
Some(f) => f,
|
||||||
None => {
|
None => {
|
||||||
return error!(
|
return error!(
|
||||||
@@ -373,7 +373,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
args,
|
args,
|
||||||
} => {
|
} => {
|
||||||
if let Expr::Variable(callee_name) = &**callee {
|
if let Expr::Variable(callee_name) = &**callee {
|
||||||
if let Some(fn_type) = self.analyzer.functions.get(&callee_name.lexeme) {
|
if let Some(fn_type) = self.symbol_table.functions.get(&callee_name.lexeme) {
|
||||||
// its a function (defined/builtin/extern)
|
// its a function (defined/builtin/extern)
|
||||||
if let Some(params) = fn_type.params.clone() {
|
if let Some(params) = fn_type.params.clone() {
|
||||||
if params.len() != args.len() {
|
if params.len() != args.len() {
|
||||||
@@ -432,7 +432,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
Expr::AddrOf { op, expr } => match expr.as_ref() {
|
Expr::AddrOf { op, expr } => match expr.as_ref() {
|
||||||
Expr::Variable(name) => {
|
Expr::Variable(name) => {
|
||||||
if self.analyzer.functions.contains_key(&name.lexeme) {
|
if self.symbol_table.functions.contains_key(&name.lexeme) {
|
||||||
Ok("fnptr".into())
|
Ok("fnptr".into())
|
||||||
} else {
|
} else {
|
||||||
Ok("ptr".into())
|
Ok("ptr".into())
|
||||||
@@ -443,7 +443,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Expr::New(struct_name) => {
|
Expr::New(struct_name) => {
|
||||||
if !self.analyzer.structs.contains_key(&struct_name.lexeme) {
|
if !self.symbol_table.structs.contains_key(&struct_name.lexeme) {
|
||||||
return error!(
|
return error!(
|
||||||
&struct_name.loc,
|
&struct_name.loc,
|
||||||
format!("unknown struct name: {}", &struct_name.lexeme)
|
format!("unknown struct name: {}", &struct_name.lexeme)
|
||||||
@@ -454,7 +454,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
Expr::MemberAccess { left, field } => {
|
Expr::MemberAccess { left, field } => {
|
||||||
let left_type = self.typecheck_expr(env, left)?;
|
let left_type = self.typecheck_expr(env, left)?;
|
||||||
|
|
||||||
let fields = match self.analyzer.structs.get(&left_type) {
|
let fields = match self.symbol_table.structs.get(&left_type) {
|
||||||
Some(f) => f,
|
Some(f) => f,
|
||||||
None => {
|
None => {
|
||||||
return error!(&field.loc, format!("unknown struct type: {}", left_type));
|
return error!(&field.loc, format!("unknown struct type: {}", left_type));
|
||||||
@@ -485,7 +485,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
if BUILTIN_TYPES.contains(&name) {
|
if BUILTIN_TYPES.contains(&name) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if self.analyzer.structs.contains_key(name) {
|
if self.symbol_table.structs.contains_key(name) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
|
|||||||
Reference in New Issue
Block a user