Почему бы не подурачиться 1 апреля. Думаю, парсер грамматики Си вполне сойдёт за дурацкую затею. Тем более я ж не сам напрягаться собираюсь, а ИИ подряжу. Я упоминал про ASDL, а есть ещё Ungrammar, другой способ описывать синтаксические деревья. Я попросил Грок сбацать мне грамматику языка Си. Он предложил упрощённый вариант:
В качестве теста обработаем Си-шную программу:
Неплохо, вполне годится. А теперь говорю, напиши парсер этой грамматики на Rust. С третьей попытки получился работающий код: c_parser/src/main.rs. Полтыщи строк нетривиального кода одним махом побиваши.// Top-level program structure
TranslationUnit = Declaration*
// Declarations
Declaration = Type Identifier ';'
| Type Identifier '(' ParameterList ')' CompoundStmt
ParameterList = (Type Identifier (',' Type Identifier)*)?
// Types
Type = 'int'
| 'float'
| 'char'
| 'void'
// Statements
Stmt = CompoundStmt
| ExprStmt
| IfStmt
| WhileStmt
| ReturnStmt
CompoundStmt = '{' Declaration* Stmt* '}'
ExprStmt = Expr ';'
IfStmt = 'if' '(' Expr ')' Stmt ('else' Stmt)?
WhileStmt = 'while' '(' Expr ')' Stmt
ReturnStmt = 'return' Expr? ';'
// Expressions
Expr = AssignmentExpr
AssignmentExpr = EqualityExpr ('=' EqualityExpr)?
EqualityExpr = RelationalExpr (('==' | '!=') RelationalExpr)?
RelationalExpr = AddExpr (('<' | '>' | '<=' | '>=') AddExpr)?
AddExpr = MultExpr (('+' | '-') MultExpr)*
MultExpr = UnaryExpr (('*' | '/') UnaryExpr)*
UnaryExpr = PrimaryExpr
| '-' UnaryExpr
| '!' UnaryExpr
PrimaryExpr = Identifier
| Number
| String
| '(' Expr ')'
// Basic tokens
Identifier = <token>
Number = <token>
String = <token>
В качестве теста обработаем Си-шную программу:
Компилируем, запускаем:int x = 42;
int main(int argc) {
int y = 3 + 5 * 2;
if (y > x) {
return 1;
} else {
return 0;
}
}
Остаётся добавить указатели, массивы, структуры, тайпдефы и прочие фичи, и язык Си у нас в кармане. 😀$ cargo run ...
Running `/home/vak/c_parser/target/debug/c_parser`
( результат )