|
|
@@ -4,10 +4,12 @@ use crate::lexer::{Token, ImmediateValue};
|
|
|
use crate::section::{CodeSection, DataSection};
|
|
|
use crate::astnode::{ASTNode, Directive, GlobalDecl, EquDecl, ExternDecl, RodataDecl, Label, Instruction, ROData};
|
|
|
use crate::dynsym::{DynamicSymbolMap, RelDynMap, RelocationType};
|
|
|
-use crate::debuginfo::span_to_line_number;
|
|
|
use codespan_reporting::files::SimpleFile;
|
|
|
use num_traits::FromPrimitive;
|
|
|
use std::collections::HashMap;
|
|
|
+use crate::errors::CompileError;
|
|
|
+use crate::messages::*;
|
|
|
+use crate::bug;
|
|
|
|
|
|
pub struct Parser<> {
|
|
|
tokens: Vec<Token>,
|
|
|
@@ -38,42 +40,45 @@ pub struct ParseResult {
|
|
|
|
|
|
pub relocation_data: RelDynMap,
|
|
|
|
|
|
- // TODO: this should determine by if there's any dynamic symbol
|
|
|
+ // TODO: this can be removed and dynamic-ness should just be
|
|
|
+ // determined by if there's any dynamic symbol
|
|
|
pub prog_is_static: bool,
|
|
|
}
|
|
|
|
|
|
+// for now, we only return one error per parse for simpler error handling
|
|
|
pub trait Parse {
|
|
|
- fn parse(tokens: &[Token]) -> Option<(Self, &[Token])>
|
|
|
+ fn parse(tokens: &[Token]) -> Result<(Self, &[Token]), CompileError>
|
|
|
where Self: Sized;
|
|
|
}
|
|
|
|
|
|
-// can maybe be removed
|
|
|
pub trait ParseInstruction {
|
|
|
- fn parse_instruction<'a>(tokens: &'a [Token], const_map: &HashMap<String, ImmediateValue>) -> Option<(Self, &'a [Token])>
|
|
|
+ fn parse_instruction<'a>(tokens: &'a [Token], const_map: &HashMap<String, ImmediateValue>) -> Result<(Self, &'a [Token]), CompileError>
|
|
|
where Self: Sized;
|
|
|
}
|
|
|
|
|
|
impl Parse for GlobalDecl {
|
|
|
- fn parse(tokens: &[Token]) -> Option<(Self, &[Token])> {
|
|
|
+ fn parse(tokens: &[Token]) -> Result<(Self, &[Token]), CompileError> {
|
|
|
+ let Token::Directive(_, span) = &tokens[0] else { bug!("GlobalDecl not a valid directive") };
|
|
|
if tokens.len() < 2 {
|
|
|
- return None;
|
|
|
+ return Err(CompileError::InvalidGlobalDecl { span: span.clone(), custom_label: None });
|
|
|
}
|
|
|
match &tokens[1] {
|
|
|
- Token::Identifier(name, span) => Some((
|
|
|
+ Token::Identifier(name, span) => Ok((
|
|
|
GlobalDecl {
|
|
|
entry_label: name.clone(),
|
|
|
span: span.clone()
|
|
|
},
|
|
|
&tokens[2..])),
|
|
|
- _ => None,
|
|
|
+ _ => Err(CompileError::InvalidGlobalDecl { span: span.clone(), custom_label: None }),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
impl Parse for EquDecl {
|
|
|
- fn parse(tokens: &[Token]) -> Option<(Self, &[Token])> {
|
|
|
+ fn parse(tokens: &[Token]) -> Result<(Self, &[Token]), CompileError> {
|
|
|
+ let Token::Directive(_, span) = &tokens[0] else { bug!("EquDecl not a valid directive") };
|
|
|
if tokens.len() < 3 {
|
|
|
- return None;
|
|
|
+ return Err(CompileError::InvalidEquDecl { span: span.clone(), custom_label: Some(EXPECTS_MORE_OPERAND.to_string()) });
|
|
|
}
|
|
|
match (
|
|
|
&tokens[1],
|
|
|
@@ -85,25 +90,25 @@ impl Parse for EquDecl {
|
|
|
Token::Comma(_),
|
|
|
Token::ImmediateValue(_value, _)
|
|
|
) => {
|
|
|
- Some((
|
|
|
+ Ok((
|
|
|
EquDecl {
|
|
|
name: name.clone(),
|
|
|
- // TODO: infer the number type from the value
|
|
|
value: tokens[3].clone(),
|
|
|
span: span.clone()
|
|
|
},
|
|
|
&tokens[4..]
|
|
|
))
|
|
|
}
|
|
|
- _ => None,
|
|
|
+ _ => Err(CompileError::InvalidEquDecl { span: span.clone(), custom_label: Some(EXPECTS_IDEN_COM_IMM.to_string()) }),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
impl Parse for ExternDecl {
|
|
|
- fn parse(tokens: &[Token]) -> Option<(Self, &[Token])> {
|
|
|
+ fn parse(tokens: &[Token]) -> Result<(Self, &[Token]), CompileError> {
|
|
|
+ let Token::Directive(_, span) = &tokens[0] else { bug!("ExternDecl not a valid directive") };
|
|
|
if tokens.len() < 2 {
|
|
|
- return None;
|
|
|
+ return Err(CompileError::InvalidExternDecl { span: span.clone(), custom_label: Some(EXPECTS_MORE_OPERAND.to_string()) });
|
|
|
}
|
|
|
let mut args = Vec::new();
|
|
|
let mut i = 1;
|
|
|
@@ -120,10 +125,9 @@ impl Parse for ExternDecl {
|
|
|
}
|
|
|
//
|
|
|
if args.is_empty() {
|
|
|
- None
|
|
|
+ Err(CompileError::InvalidExternDecl { span: span.clone(), custom_label: Some(EXPECTS_IDEN.to_string()) })
|
|
|
} else {
|
|
|
- let Token::Directive(_, span) = &tokens[0] else { unreachable!() };
|
|
|
- Some((
|
|
|
+ Ok((
|
|
|
ExternDecl {
|
|
|
args,
|
|
|
span: span.clone()
|
|
|
@@ -135,9 +139,10 @@ impl Parse for ExternDecl {
|
|
|
}
|
|
|
|
|
|
impl Parse for ROData {
|
|
|
- fn parse(tokens: &[Token]) -> Option<(Self, &[Token])> {
|
|
|
+ fn parse(tokens: &[Token]) -> Result<(Self, &[Token]), CompileError> {
|
|
|
+ let Token::Directive(_, span) = &tokens[0] else { bug!("ROData not a valid directive") };
|
|
|
if tokens.len() < 3 {
|
|
|
- return None;
|
|
|
+ return Err(CompileError::InvalidRodataDecl { span: span.clone(), custom_label: Some(EXPECTS_MORE_OPERAND.to_string()) });
|
|
|
}
|
|
|
|
|
|
let mut args = Vec::new();
|
|
|
@@ -153,7 +158,7 @@ impl Parse for ROData {
|
|
|
) => {
|
|
|
args.push(tokens[1].clone());
|
|
|
args.push(tokens[2].clone());
|
|
|
- Some((
|
|
|
+ Ok((
|
|
|
ROData {
|
|
|
name: name.clone(),
|
|
|
args,
|
|
|
@@ -162,13 +167,13 @@ impl Parse for ROData {
|
|
|
&tokens[3..]
|
|
|
))
|
|
|
}
|
|
|
- _ => None,
|
|
|
+ _ => Err(CompileError::InvalidRodataDecl { span: span.clone(), custom_label: Some(EXPECTS_LABEL_DIR_STR.to_string()) }),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
impl ParseInstruction for Instruction {
|
|
|
- fn parse_instruction<'a>(tokens: &'a [Token], const_map: &HashMap<String, ImmediateValue>) -> Option<(Self, &'a [Token])> {
|
|
|
+ fn parse_instruction<'a>(tokens: &'a [Token], const_map: &HashMap<String, ImmediateValue>) -> Result<(Self, &'a [Token]), CompileError> {
|
|
|
let next_token_num;
|
|
|
match &tokens[0] {
|
|
|
Token::Opcode(opcode, span) => {
|
|
|
@@ -177,7 +182,11 @@ impl ParseInstruction for Instruction {
|
|
|
match opcode {
|
|
|
Opcode::Lddw => {
|
|
|
if tokens.len() < 4 {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_MORE_OPERAND.to_string()) });
|
|
|
}
|
|
|
let (value, advance_token_num) = inline_and_fold_constant(tokens, const_map, 3);
|
|
|
if let Some(value) = value {
|
|
|
@@ -195,7 +204,11 @@ impl ParseInstruction for Instruction {
|
|
|
operands.push(Token::ImmediateValue(value, span.clone()));
|
|
|
}
|
|
|
_ => {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_REG_COM_IMM_OR_IDEN.to_string()) });
|
|
|
}
|
|
|
}
|
|
|
next_token_num = advance_token_num;
|
|
|
@@ -213,9 +226,12 @@ impl ParseInstruction for Instruction {
|
|
|
operands.push(tokens[1].clone());
|
|
|
operands.push(tokens[3].clone());
|
|
|
}
|
|
|
- // external error: invalid syntax with opcode: lddw
|
|
|
_ => {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_REG_COM_IMM_OR_IDEN.to_string()) });
|
|
|
}
|
|
|
}
|
|
|
next_token_num = 4;
|
|
|
@@ -223,7 +239,11 @@ impl ParseInstruction for Instruction {
|
|
|
}
|
|
|
Opcode::Ldxw | Opcode::Ldxh | Opcode::Ldxb | Opcode::Ldxdw => {
|
|
|
if tokens.len() < 8 {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_MORE_OPERAND.to_string()) });
|
|
|
}
|
|
|
let (value, advance_token_num) = inline_and_fold_constant(tokens, const_map, 6);
|
|
|
if let Some(value) = value {
|
|
|
@@ -250,18 +270,30 @@ impl ParseInstruction for Instruction {
|
|
|
operands.push(Token::ImmediateValue(value, span.clone()));
|
|
|
}
|
|
|
_ => {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_REG_COM_LB_REG_BIOP_IMM_RB.to_string()) });
|
|
|
}
|
|
|
}
|
|
|
next_token_num = advance_token_num + 1;
|
|
|
} else {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_REG_COM_LB_REG_BIOP_IMM_RB.to_string()) });
|
|
|
}
|
|
|
}
|
|
|
Opcode::Stw | Opcode::Sth | Opcode::Stb | Opcode::Stdw
|
|
|
| Opcode::Stxb | Opcode::Stxh | Opcode::Stxw | Opcode::Stxdw => {
|
|
|
if tokens.len() < 8 {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_MORE_OPERAND.to_string()) });
|
|
|
}
|
|
|
let (value, advance_token_num) = inline_and_fold_constant(tokens, const_map, 4);
|
|
|
if let Some(value) = value {
|
|
|
@@ -288,12 +320,20 @@ impl ParseInstruction for Instruction {
|
|
|
operands.push(tokens[advance_token_num + 2].clone());
|
|
|
}
|
|
|
_ => {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_LB_REG_BIOP_IMM_RB_COM_REG.to_string()) });
|
|
|
}
|
|
|
}
|
|
|
next_token_num = advance_token_num + 3;
|
|
|
} else {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_LB_REG_BIOP_IMM_RB_COM_REG.to_string()) });
|
|
|
}
|
|
|
}
|
|
|
Opcode::Add32 | Opcode::Sub32 | Opcode::Mul32
|
|
|
@@ -309,7 +349,11 @@ impl ParseInstruction for Instruction {
|
|
|
| Opcode::Lmul64 | Opcode::Uhmul64 | Opcode::Udiv64
|
|
|
| Opcode::Urem64 | Opcode::Sdiv64 | Opcode::Srem64 => {
|
|
|
if tokens.len() < 4 {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_MORE_OPERAND.to_string()) });
|
|
|
}
|
|
|
let (value, advance_token_num) = inline_and_fold_constant(tokens, const_map, 3);
|
|
|
if let Some(value) = value {
|
|
|
@@ -328,7 +372,11 @@ impl ParseInstruction for Instruction {
|
|
|
operands.push(Token::ImmediateValue(value, span.clone()));
|
|
|
}
|
|
|
_ => {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_REG_COM_IMM.to_string()) });
|
|
|
}
|
|
|
}
|
|
|
next_token_num = advance_token_num;
|
|
|
@@ -348,7 +396,11 @@ impl ParseInstruction for Instruction {
|
|
|
operands.push(tokens[3].clone());
|
|
|
}
|
|
|
_ => {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_REG_COM_REG.to_string()) });
|
|
|
}
|
|
|
}
|
|
|
next_token_num = 4;
|
|
|
@@ -359,7 +411,11 @@ impl ParseInstruction for Instruction {
|
|
|
| Opcode::Jne | Opcode::Jsgt | Opcode::Jsge
|
|
|
| Opcode::Jslt | Opcode::Jsle => {
|
|
|
if tokens.len() < 6 {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_MORE_OPERAND.to_string()) });
|
|
|
}
|
|
|
let (value, advance_token_num) = inline_and_fold_constant(tokens, const_map, 3);
|
|
|
if let Some(value) = value {
|
|
|
@@ -383,7 +439,11 @@ impl ParseInstruction for Instruction {
|
|
|
operands.push(tokens[advance_token_num + 1].clone());
|
|
|
}
|
|
|
_ => {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_REG_COM_IMM_COM_IMM_OR_IDEN.to_string()) });
|
|
|
}
|
|
|
}
|
|
|
next_token_num = advance_token_num + 2;
|
|
|
@@ -402,13 +462,18 @@ impl ParseInstruction for Instruction {
|
|
|
Token::Comma(_),
|
|
|
Token::Identifier(_, _)
|
|
|
) => {
|
|
|
+ // turn "invalid opcode" to a bug
|
|
|
opcode = FromPrimitive::from_u8((opcode as u8) + 2).expect("Invalid opcode conversion");
|
|
|
operands.push(tokens[1].clone());
|
|
|
operands.push(tokens[3].clone());
|
|
|
operands.push(tokens[5].clone());
|
|
|
}
|
|
|
_ => {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_REG_COM_IMM_COM_IMM_OR_IDEN.to_string()) });
|
|
|
}
|
|
|
}
|
|
|
next_token_num = 6;
|
|
|
@@ -416,7 +481,11 @@ impl ParseInstruction for Instruction {
|
|
|
}
|
|
|
Opcode::Ja => {
|
|
|
if tokens.len() < 2 {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_MORE_OPERAND.to_string()) });
|
|
|
}
|
|
|
let (value, advance_token_num) = inline_and_fold_constant(tokens, const_map, 1);
|
|
|
if let Some(value) = value {
|
|
|
@@ -428,7 +497,11 @@ impl ParseInstruction for Instruction {
|
|
|
operands.push(tokens[1].clone());
|
|
|
}
|
|
|
_ => {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_IDEN.to_string()) });
|
|
|
}
|
|
|
}
|
|
|
next_token_num = 2;
|
|
|
@@ -436,14 +509,22 @@ impl ParseInstruction for Instruction {
|
|
|
}
|
|
|
Opcode::Call => {
|
|
|
if tokens.len() < 2 {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_MORE_OPERAND.to_string()) });
|
|
|
}
|
|
|
match &tokens[1] {
|
|
|
Token::Identifier(_, _) => {
|
|
|
operands.push(tokens[1].clone());
|
|
|
}
|
|
|
_ => {
|
|
|
- return None;
|
|
|
+ return Err(
|
|
|
+ CompileError::InvalidInstruction { //
|
|
|
+ instruction: opcode.to_string() //
|
|
|
+ , span: span.clone() //
|
|
|
+ , custom_label: Some(EXPECTS_IDEN.to_string()) });
|
|
|
}
|
|
|
}
|
|
|
next_token_num = 2;
|
|
|
@@ -451,12 +532,11 @@ impl ParseInstruction for Instruction {
|
|
|
Opcode::Exit => {
|
|
|
next_token_num = 1;
|
|
|
}
|
|
|
- // internal error: invalid opcode
|
|
|
_ => {
|
|
|
- return None;
|
|
|
+ bug!("invalid opcode: {}", opcode.to_str());
|
|
|
}
|
|
|
}
|
|
|
- Some((
|
|
|
+ Ok((
|
|
|
Instruction {
|
|
|
opcode,
|
|
|
operands,
|
|
|
@@ -465,7 +545,9 @@ impl ParseInstruction for Instruction {
|
|
|
&tokens[next_token_num..]
|
|
|
))
|
|
|
}
|
|
|
- _ => None,
|
|
|
+ _ => {
|
|
|
+ bug!("invalid instruction");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
}
|
|
|
@@ -534,32 +616,50 @@ impl Parser {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- pub fn parse(&mut self) -> Result<ParseResult, String> {
|
|
|
+ pub fn parse(&mut self) -> Result<ParseResult, Vec<CompileError>> {
|
|
|
let mut nodes = Vec::new();
|
|
|
let mut rodata_nodes = Vec::new();
|
|
|
let mut rodata_phase = false;
|
|
|
|
|
|
+ let mut errors = Vec::new();
|
|
|
+
|
|
|
let mut tokens = self.tokens.as_slice();
|
|
|
|
|
|
+ // TODO: when parse error occurs, we should probably just jump to the next line
|
|
|
+ // if we're able to error out the scenario where users put 2 instructions in the same line
|
|
|
+ // for now we just continue to the next token
|
|
|
+
|
|
|
+ // TODO: it would be nice if we build a token iterator that can
|
|
|
+ // 1. peek the next multiple tokens (for detecting patterns)
|
|
|
+ // 2. jump to the next line
|
|
|
+ // 3. continue to the next token
|
|
|
while !tokens.is_empty() {
|
|
|
match &tokens[0] {
|
|
|
Token::Directive(name, span) => {
|
|
|
match name.as_str() {
|
|
|
"global" | "globl" => {
|
|
|
- if let Some((node, rest)) = GlobalDecl::parse(tokens) {
|
|
|
+ match GlobalDecl::parse(tokens) {
|
|
|
+ Ok((node, rest)) => {
|
|
|
self.m_entry_label = Some(node.get_entry_label());
|
|
|
nodes.push(ASTNode::GlobalDecl { global_decl: node });
|
|
|
tokens = rest;
|
|
|
- } else {
|
|
|
- return Err("Invalid global declaration".to_string());
|
|
|
+ }
|
|
|
+ Err(e) => {
|
|
|
+ errors.push(e);
|
|
|
+ tokens = &tokens[1..];
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
"extern" => {
|
|
|
- if let Some((node, rest)) = ExternDecl::parse(tokens) {
|
|
|
+ match ExternDecl::parse(tokens) {
|
|
|
+ Ok((node, rest)) => {
|
|
|
nodes.push(ASTNode::ExternDecl { extern_decl: node });
|
|
|
tokens = rest;
|
|
|
- } else {
|
|
|
- return Err("Invalid extern declaration".to_string());
|
|
|
+ }
|
|
|
+ Err(e) => {
|
|
|
+ errors.push(e);
|
|
|
+ tokens = &tokens[1..];
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
"rodata" => {
|
|
|
@@ -568,12 +668,16 @@ impl Parser {
|
|
|
tokens = &tokens[1..];
|
|
|
}
|
|
|
"equ" => {
|
|
|
- if let Some((node, rest)) = EquDecl::parse(tokens) {
|
|
|
+ match EquDecl::parse(tokens) {
|
|
|
+ Ok((node, rest)) => {
|
|
|
self.m_const_map.insert(node.get_name(), node.get_val());
|
|
|
nodes.push(ASTNode::EquDecl { equ_decl: node });
|
|
|
tokens = rest;
|
|
|
- } else {
|
|
|
- return Err("Invalid equ declaration".to_string());
|
|
|
+ }
|
|
|
+ Err(e) => {
|
|
|
+ errors.push(e);
|
|
|
+ tokens = &tokens[1..];
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
"section" => {
|
|
|
@@ -581,19 +685,24 @@ impl Parser {
|
|
|
tokens = &tokens[1..];
|
|
|
}
|
|
|
_ => {
|
|
|
- return Err(format!("Invalid directive: {}", name));
|
|
|
+ errors.push(CompileError::InvalidDirective { directive: name.clone(), span: span.clone(), custom_label: None });
|
|
|
+ tokens = &tokens[1..];
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
Token::Label(name, span) => {
|
|
|
if rodata_phase {
|
|
|
- if let Some((rodata, rest)) = ROData::parse(tokens) {
|
|
|
+ match ROData::parse(tokens) {
|
|
|
+ Ok((rodata, rest)) => {
|
|
|
self.m_label_offsets.insert(name.clone(), self.m_accum_offset + self.m_rodata_size);
|
|
|
self.m_rodata_size += rodata.get_size();
|
|
|
rodata_nodes.push(ASTNode::ROData { rodata, offset: self.m_accum_offset });
|
|
|
tokens = rest;
|
|
|
- } else {
|
|
|
- return Err("Invalid rodata declaration".to_string());
|
|
|
+ }
|
|
|
+ Err(e) => {
|
|
|
+ errors.push(e);
|
|
|
+ tokens = &tokens[1..];
|
|
|
+ }
|
|
|
}
|
|
|
} else {
|
|
|
self.m_label_offsets.insert(name.clone(), self.m_accum_offset);
|
|
|
@@ -601,30 +710,38 @@ impl Parser {
|
|
|
tokens = &tokens[1..];
|
|
|
}
|
|
|
}
|
|
|
- Token::Opcode(_opcode, span) => {
|
|
|
- if let Some((inst, rest)) = Instruction::parse_instruction(tokens, &self.m_const_map) {
|
|
|
- if inst.needs_relocation() {
|
|
|
- self.m_prog_is_static = false;
|
|
|
- let (reloc_type, label) = inst.get_relocation_info();
|
|
|
- self.m_rel_dyns.add_rel_dyn(self.m_accum_offset, reloc_type, label.clone());
|
|
|
- if reloc_type == RelocationType::RSbfSyscall {
|
|
|
- self.m_dynamic_symbols.add_call_target(label.clone(), self.m_accum_offset);
|
|
|
+ Token::Opcode(_, _) => {
|
|
|
+ match Instruction::parse_instruction(tokens, &self.m_const_map) {
|
|
|
+ Ok((inst, rest)) => {
|
|
|
+ if inst.needs_relocation() {
|
|
|
+ self.m_prog_is_static = false;
|
|
|
+ let (reloc_type, label) = inst.get_relocation_info();
|
|
|
+ self.m_rel_dyns.add_rel_dyn(self.m_accum_offset, reloc_type, label.clone());
|
|
|
+ if reloc_type == RelocationType::RSbfSyscall {
|
|
|
+ self.m_dynamic_symbols.add_call_target(label.clone(), self.m_accum_offset);
|
|
|
+ }
|
|
|
}
|
|
|
+ let offset = self.m_accum_offset;
|
|
|
+ self.m_accum_offset += inst.get_size();
|
|
|
+ nodes.push(ASTNode::Instruction { instruction: inst, offset });
|
|
|
+ tokens = rest;
|
|
|
+ }
|
|
|
+ Err(e) => {
|
|
|
+ errors.push(e);
|
|
|
+ tokens = &tokens[1..];
|
|
|
}
|
|
|
- let offset = self.m_accum_offset;
|
|
|
- self.m_accum_offset += inst.get_size();
|
|
|
- nodes.push(ASTNode::Instruction { instruction: inst, offset });
|
|
|
- tokens = rest;
|
|
|
- } else {
|
|
|
- return Err(format!("Invalid instruction at line {}", span_to_line_number(span.clone(), self.m_file.as_ref().unwrap())));
|
|
|
}
|
|
|
}
|
|
|
_ => {
|
|
|
- return Err(format!("Unexpected token: {:?}", tokens[0]));
|
|
|
+ tokens = &tokens[1..];
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if !errors.is_empty() {
|
|
|
+ return Err(errors);
|
|
|
+ }
|
|
|
+
|
|
|
// Second pass to resolve labels
|
|
|
for node in &mut nodes {
|
|
|
match node {
|
|
|
@@ -656,6 +773,8 @@ impl Parser {
|
|
|
// Replace label with immediate value
|
|
|
let last_idx = operands.len() - 1;
|
|
|
operands[last_idx] = Token::ImmediateValue(ImmediateValue::Addr(abs_offset), span.clone());
|
|
|
+ } else {
|
|
|
+ errors.push(CompileError::UndefinedLabel { label: name.clone(), span: span.clone(), custom_label: None });
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -670,13 +789,17 @@ impl Parser {
|
|
|
self.m_dynamic_symbols.add_entry_point(entry_label.clone(), *offset);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- Ok(ParseResult {
|
|
|
- code_section: CodeSection::new(nodes, self.m_accum_offset, self.m_file.as_ref().unwrap()),
|
|
|
- data_section: DataSection::new(rodata_nodes, self.m_rodata_size),
|
|
|
- dynamic_symbols: DynamicSymbolMap::copy(&self.m_dynamic_symbols),
|
|
|
- relocation_data: RelDynMap::copy(&self.m_rel_dyns),
|
|
|
- prog_is_static: self.m_prog_is_static,
|
|
|
- })
|
|
|
+
|
|
|
+ if !errors.is_empty() {
|
|
|
+ return Err(errors);
|
|
|
+ } else {
|
|
|
+ Ok(ParseResult {
|
|
|
+ code_section: CodeSection::new(nodes, self.m_accum_offset, self.m_file.as_ref().unwrap()),
|
|
|
+ data_section: DataSection::new(rodata_nodes, self.m_rodata_size),
|
|
|
+ dynamic_symbols: DynamicSymbolMap::copy(&self.m_dynamic_symbols),
|
|
|
+ relocation_data: RelDynMap::copy(&self.m_rel_dyns),
|
|
|
+ prog_is_static: self.m_prog_is_static,
|
|
|
+ })
|
|
|
+ }
|
|
|
}
|
|
|
}
|