Struct SymbolTable

Source
pub struct SymbolTable { /* private fields */ }
Expand description

The symbol table created in the first assembler pass that encodes source code mappings to memory addresses in the object file.

The symbol table consists of:

  • A mapping from source code labels to memory addresses.
  • A mapping from source code line numbers to memory addresses (if debug symbols are enabled).
  • The source text (if debug symbols are enabled).

Here is a table of the mappings that the symbol table provides:

from ↓, to →labelmemory addresssource line/span
label-SymbolTable::lookup_labelSymbolTable::get_label_source
memory addressSymbolTable::rev_lookup_label-SymbolTable::rev_lookup_line
source linenoneSymbolTable::lookup_line-

§Debug symbols

Debug symbols are optional data added to this symbol table which can help users debug their code.

Without debug symbols, the symbol table only consists of mappings from labels to spans (and vice-versa). These are used to translate labels in source code to addresses during the assembly process. After the completion of this assembly process, the SymbolTable is dropped and is not part of the resultant ObjectFile.

However, with debug symbols, this information persists in the resultant ObjectFile, allowing the label mappings to be accessed during simulation time. Additionally, more information from the source text is available during simulation time:

  • Mappings from source code line numbers to memory addresses
  • Source code text (which grants access to line contents from a given line number; see SourceInfo for more details)

Implementations§

Source§

impl SymbolTable

Source

pub fn new(stmts: &[Stmt], src: Option<&str>) -> Result<Self, AsmErr>

Creates a new symbol table.

This performs the first assembler pass, calculating the memory address of labels at each provided statement.

If a src argument is provided, debug symbols are also computed for the symbol table.

§Example
use lc3_ensemble::parse::parse_ast;
use lc3_ensemble::asm::SymbolTable;
 
let src = "
    .orig x3000
    LABEL: HALT
    .end
";
let ast = parse_ast(src).unwrap();
 
// without debug symbols
let sym = SymbolTable::new(&ast, None).unwrap();
assert_eq!(sym.lookup_label("LABEL"), Some(0x3000));
assert_eq!(sym.lookup_line(2), None);
 
// with debug symbols
let sym = SymbolTable::new(&ast, Some(src)).unwrap();
assert_eq!(sym.lookup_label("LABEL"), Some(0x3000));
assert_eq!(sym.lookup_line(2), Some(0x3000));
Source

pub fn lookup_label(&self, label: &str) -> Option<u16>

Gets the memory address of a given label (if it exists).

§Example
use lc3_ensemble::parse::parse_ast;
use lc3_ensemble::asm::SymbolTable;
 
let src = "
    .orig x3000
    LOOP:
        ADD R0, R0, #1
        BR LOOP
    LOOP2:
        ADD R0, R0, #2
        BR LOOP2
    LOOP3:
        ADD R0, R0, #3
        BR LOOP3
    .end
";
let ast = parse_ast(src).unwrap();
 
let sym = SymbolTable::new(&ast, None).unwrap();
assert_eq!(sym.lookup_label("LOOP"), Some(0x3000));
assert_eq!(sym.lookup_label("LOOP2"), Some(0x3002));
assert_eq!(sym.lookup_label("LOOP3"), Some(0x3004));
assert_eq!(sym.lookup_label("LOOP_DE_LOOP"), None);
Source

pub fn rev_lookup_label(&self, addr: u16) -> Option<&str>

Gets the label at a given memory address (if it exists).

§Example
use lc3_ensemble::parse::parse_ast;
use lc3_ensemble::asm::SymbolTable;
 
let src = "
    .orig x3000
    LOOP:
        ADD R0, R0, #1
        BR LOOP
    LOOP2:
        ADD R0, R0, #2
        BR LOOP2
    LOOP3:
        ADD R0, R0, #3
        BR LOOP3
    .end
";
let ast = parse_ast(src).unwrap();
 
let sym = SymbolTable::new(&ast, None).unwrap();
assert_eq!(sym.rev_lookup_label(0x3000), Some("LOOP"));
assert_eq!(sym.rev_lookup_label(0x3002), Some("LOOP2"));
assert_eq!(sym.rev_lookup_label(0x3004), Some("LOOP3"));
assert_eq!(sym.rev_lookup_label(0x2110), None);
Source

pub fn get_label_source(&self, label: &str) -> Option<Range<usize>>

Gets the source span of a given label (if it exists).

§Example
use lc3_ensemble::parse::parse_ast;
use lc3_ensemble::asm::SymbolTable;
 
let src = "
    .orig x3000
    LOOPY:
        ADD R0, R0, #1
        BR LOOPY
    .end
";
let ast = parse_ast(src).unwrap();
 
let sym = SymbolTable::new(&ast, None).unwrap();
assert_eq!(sym.get_label_source("LOOPY"), Some(21..26));
assert_eq!(sym.get_label_source("LOOP_DE_LOOP"), None);
Source

pub fn lookup_line(&self, line: usize) -> Option<u16>

Gets the address of a given source line.

If debug symbols are not enabled, this unconditionally returns None. Note that each address is mapped to at most one source code line.

§Example
use lc3_ensemble::parse::parse_ast;
use lc3_ensemble::asm::SymbolTable;
 
let src = "              ;;  0
    .orig x3000          ;;  1
    LOOP:                ;;  2
        ADD R0, R0, #1   ;;  3
        BR LOOP          ;;  4
    .fill x9999          ;;  5
    .blkw 10             ;;  6
    LOOP2:               ;;  7
        ADD R0, R0, #3   ;;  8
        BR LOOP3         ;;  9
    .end                 ;; 10
";
let ast = parse_ast(src).unwrap();
 
// Debug symbols required:
let sym = SymbolTable::new(&ast, Some(src)).unwrap();
assert_eq!(sym.lookup_line(0),  None);
assert_eq!(sym.lookup_line(1),  None);
assert_eq!(sym.lookup_line(2),  None);
assert_eq!(sym.lookup_line(3),  Some(0x3000));
assert_eq!(sym.lookup_line(4),  Some(0x3001));
assert_eq!(sym.lookup_line(5),  Some(0x3002));
assert_eq!(sym.lookup_line(6),  Some(0x3003));
assert_eq!(sym.lookup_line(7),  None);
assert_eq!(sym.lookup_line(8),  Some(0x300D));
assert_eq!(sym.lookup_line(9),  Some(0x300E));
assert_eq!(sym.lookup_line(10), None);
Source

pub fn rev_lookup_line(&self, addr: u16) -> Option<usize>

Gets the source line of a given memory address (if it exists.)

The result can be converted into a source span (range of characters encompassed by the instruction) using SymbolTable::source_info and SourceInfo::line_span.

If debug symbols are not enabled, this unconditionally returns None. Note that each source code line is mapped to at most one address.

§Example
use lc3_ensemble::parse::parse_ast;
use lc3_ensemble::asm::SymbolTable;
 
let src = "              ;;  0
    .orig x3000          ;;  1
    LOOP:                ;;  2
        ADD R0, R0, #1   ;;  3
        BR LOOP          ;;  4
    .fill x9999          ;;  5
    .blkw 10             ;;  6
    LOOP2:               ;;  7
        ADD R0, R0, #3   ;;  8
        BR LOOP3         ;;  9
    .end                 ;; 10
";
let ast = parse_ast(src).unwrap();
 
// Debug symbols required:
let sym = SymbolTable::new(&ast, Some(src)).unwrap();
assert_eq!(sym.rev_lookup_line(0x3000),  Some(3));
assert_eq!(sym.rev_lookup_line(0x3001),  Some(4));
assert_eq!(sym.rev_lookup_line(0x3002),  Some(5));
assert_eq!(sym.rev_lookup_line(0x3003),  Some(6));
assert_eq!(sym.rev_lookup_line(0x3004),  None);
assert_eq!(sym.rev_lookup_line(0x3005),  None);
assert_eq!(sym.rev_lookup_line(0x3006),  None);
assert_eq!(sym.rev_lookup_line(0x3007),  None);
assert_eq!(sym.rev_lookup_line(0x3008),  None);
assert_eq!(sym.rev_lookup_line(0x3009),  None);
assert_eq!(sym.rev_lookup_line(0x300A),  None);
assert_eq!(sym.rev_lookup_line(0x300B),  None);
assert_eq!(sym.rev_lookup_line(0x300C),  None);
assert_eq!(sym.rev_lookup_line(0x300D),  Some(8));
assert_eq!(sym.rev_lookup_line(0x300E),  Some(9));
assert_eq!(sym.rev_lookup_line(0x300F),  None);
Source

pub fn source_info(&self) -> Option<&SourceInfo>

Reads the source info from this symbol table (if debug symbols are enabled).

Source

pub fn label_iter(&self) -> impl Iterator<Item = (&str, u16, bool)> + '_

Gets an iterable of the mapping from labels to addresses.

Source

pub fn line_iter(&self) -> impl Iterator<Item = (usize, u16)> + '_

Gets an iterable of the mapping from lines to addresses.

This iterator will be empty if debug symbols were not enabled.

Trait Implementations§

Source§

impl Clone for SymbolTable

Source§

fn clone(&self) -> SymbolTable

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for SymbolTable

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for SymbolTable

Source§

fn eq(&self, other: &SymbolTable) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for SymbolTable

Source§

impl StructuralPartialEq for SymbolTable

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V