add lexer
This commit is contained in:
parent
05ad6afe72
commit
ad7a8ad879
3 changed files with 120 additions and 2 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1 +1,2 @@
|
||||||
/target
|
/target
|
||||||
|
/res
|
||||||
96
src/lexer.rs
Normal file
96
src/lexer.rs
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Token {
|
||||||
|
Number(i64),
|
||||||
|
Ident(String),
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
|
Mod,
|
||||||
|
|
||||||
|
// Parentheses
|
||||||
|
LParen,
|
||||||
|
RParen,
|
||||||
|
LBrace,
|
||||||
|
RBrace,
|
||||||
|
LBracket,
|
||||||
|
RBracket,
|
||||||
|
|
||||||
|
Semicolon
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Lexer {
|
||||||
|
source: Vec<u8>,
|
||||||
|
pos: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Lexer {
|
||||||
|
pub fn new(source: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
source: source.as_bytes().to_vec(),
|
||||||
|
pos: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn skip_whitespace(&mut self) {
|
||||||
|
while matches!(self.peek(), Some(c) if c.is_ascii_whitespace()) {
|
||||||
|
self.advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance(&mut self) {
|
||||||
|
self.pos += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek(&self) -> Option<u8> {
|
||||||
|
self.source.get(self.pos).copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn number(&mut self) -> Option<Token> {
|
||||||
|
let mut num = String::new();
|
||||||
|
|
||||||
|
while matches!(self.peek(), Some(b'0' ..= b'9')) {
|
||||||
|
num.push(self.peek().unwrap() as char);
|
||||||
|
self.advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Token::Number(num.parse().unwrap()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ident(&mut self) -> Option<Token> {
|
||||||
|
let mut ident = String::new();
|
||||||
|
|
||||||
|
while matches!(self.peek(), Some(b'a' ..= b'z' | b'A' ..= b'Z')) {
|
||||||
|
ident.push(self.peek().unwrap() as char);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Token::Ident(ident))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next(&mut self) -> Option<Token> {
|
||||||
|
self.skip_whitespace();
|
||||||
|
match self.peek() {
|
||||||
|
Some(b'0' ..= b'9') => self.number(),
|
||||||
|
Some(b'a' ..= b'z' | b'A' ..= b'Z') => self.ident(),
|
||||||
|
|
||||||
|
Some(b'+') => {self.advance(); Some(Token::Add)},
|
||||||
|
Some(b'-') => {self.advance(); Some(Token::Sub)},
|
||||||
|
Some(b'*') => {self.advance(); Some(Token::Mul)},
|
||||||
|
Some(b'/') => {self.advance(); Some(Token::Div)},
|
||||||
|
Some(b'%') => {self.advance(); Some(Token::Mod)},
|
||||||
|
|
||||||
|
Some(b'(') => {self.advance(); Some(Token::LParen)},
|
||||||
|
Some(b')') => {self.advance(); Some(Token::RParen)},
|
||||||
|
Some(b'[') => {self.advance(); Some(Token::LBracket)},
|
||||||
|
Some(b']') => {self.advance(); Some(Token::RBracket)},
|
||||||
|
Some(b'{') => {self.advance(); Some(Token::LBrace)},
|
||||||
|
Some(b'}') => {self.advance(); Some(Token::RBrace)},
|
||||||
|
|
||||||
|
Some(b';') => {self.advance(); Some(Token::Semicolon)}
|
||||||
|
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/main.rs
25
src/main.rs
|
|
@ -1,3 +1,24 @@
|
||||||
fn main() {
|
use std::{fs::File, io::Read};
|
||||||
println!("Hello, world!");
|
|
||||||
|
mod lexer;
|
||||||
|
use lexer::Lexer;
|
||||||
|
|
||||||
|
fn main() -> std::io::Result<()> {
|
||||||
|
let args = std::env::args().collect::<Vec<String>>();
|
||||||
|
|
||||||
|
let mut source = String::new();
|
||||||
|
File::open(&args[1])?.read_to_string(&mut source)?;
|
||||||
|
|
||||||
|
println!("{:?}", source);
|
||||||
|
|
||||||
|
let mut lexer = Lexer::new(&source);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match lexer.next() {
|
||||||
|
Some(tok) => print!("{tok:?}, "),
|
||||||
|
None => break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue