ایجاد لکسر ساده و سریع با آرم

سلام بچه ها ، این اولین پست من است. من در حال نوشتن این پست هستم که علت آن را که واقعاً دوست داشتم و از آن لذت بردم در هنگام نوشتن Tokenizer با آرم ها ، اما نمی توانستم آنچه را که می خواستم ، شاید آن را خیلی نفهمیدم اما آرم ها بسیار خوب و زیبا هستند و این دقیقاً مانند Flex است.
آرم ها چیست؟ آرم ها سریع و آسان برای استفاده از ژنراتور Lexer نوشته شده در Rust است ، بنابراین اگر می خواهید یک عمل ساده لکسینگ را در Rust انجام دهید می توانید آرم ها را انتخاب کنید ، می توانید Lexer مبتنی بر Token را با آن تهیه کنید ، همچنین در این نمونه ما یک لکسر ساده مبتنی بر Token ایجاد خواهیم کرد.
بیایید با ایجاد یک پروژه ساده شروع کنیم:
cargo new my_lexer
cd my_lexer
اکنون باید وابستگی آرم را به پروژه خود اضافه کنیم:
cargo add logos
خوب ، اکنون ما آماده شروع کار هستیم ، من با ایجاد یک فایل نمونه شروع می کنم ، می خواهم یک زنگ بسیار ساده مانند نحو را نشان دهم ، بیایید یک پرونده my_example.txt را ایجاد کنیم.
// examples/my_example.txt
fn main() {
print("hello")
}
اکنون باید مسیر پرونده را در برنامه Rust خود طی کنیم ، می توانیم از طریق استفاده از ARG ها به آن برسیم و همچنین باید پرونده گرفته شده را بخوانیم.
// src/main.rs
use std::env;
use std::fs::read_to_string;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() >= 2 {
let file = &args[1];
let ctx = read_to_string(file).expect("Should have been able to read the file");
println!("{:?}", ctx);
} else {
eprintln!("pls give me a text file.");
}
}
خوب ، بنابراین اکنون ما یک برنامه خواننده فایل ساده داریم. حال بیایید چند نشانه ایجاد کنیم.
#[derive(Logos, Debug, PartialEq)]
#[logos(skip r"[ \t\n\f]+")]
pub enum Token<'a> {
#[token("fn")]
Function,
#[token("{")]
LeftCurlyBracet,
#[token("}")]
RightCurlyBracet,
#[token("(")]
LeftBracet,
#[token(")")]
RightBracet,
#[regex(r"[a-zA-Z][a-zA-Z0-9]*")]
Text(&'a str),
#[regex(r#""([^"\\]|\\.)*""#, priority = 1)]
String(&'a str),
}
ما در اینجا چه کاری انجام دادیم؟ در مرحله اول ، ما آرم های مشتق ، فرار از مکان های سفید ، Newline ، EOF و Tab را تنظیم می کنیم ، پس از مشتق ها ، ما فقط یک رمز ساده با نشانه های خود با نشانه های مشتق ایجاد کردیم.
ما داریم:
- نشانه های استاتیک: fn ، (،) ، {،}
- متن و رشته.
و در آخر می توانیم ورودی را از بین ببریم:
// src/main.rs
use std::env;
use std::fs::read_to_string;
use logos::Logos;
#[derive(Logos, Debug, PartialEq)]
#[logos(skip r"[ \t\n\f]+")]
pub enum Token<'a> {
#[token("fn")]
Function,
#[token("{")]
LeftCurlyBracet,
#[token("}")]
RightCurlyBracet,
#[token("(")]
LeftBracet,
#[token(")")]
RightBracket,
#[regex(r"[a-zA-Z][a-zA-Z0-9]*")]
Text(&'a str),
#[regex(r#""([^"\\]|\\.)*""#, priority = 1)]
String(&'a str),
}
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() >= 2 {
let file = &args[1];
let ctx = read_to_string(file).expect("Should have been able to read the file");
for res in Token::lexer(&ctx) {
match res {
Ok(token) => println!("{:#?}", token),
Err(e) => panic!("some error occurred {:?}", e)
}
}
} else {
eprintln!("pls give me a text file.");
}
}
✨result✨