2025-04-01

vak: (Default)
Почему бы не подурачиться 1 апреля. Думаю, парсер грамматики Си вполне сойдёт за дурацкую затею. Тем более я ж не сам напрягаться собираюсь, а ИИ подряжу. Я упоминал про ASDL, а есть ещё Ungrammar, другой способ описывать синтаксические деревья. Я попросил Грок сбацать мне грамматику языка Си. Он предложил упрощённый вариант:
// 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>
Неплохо, вполне годится. А теперь говорю, напиши парсер этой грамматики на Rust. С третьей попытки получился работающий код: c_parser/src/main.rs. Полтыщи строк нетривиального кода одним махом побиваши.

В качестве теста обработаем Си-шную программу:
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`
результат )
Остаётся добавить указатели, массивы, структуры, тайпдефы и прочие фичи, и язык Си у нас в кармане. 😀