tutorial del

master
serr 2025-04-29 20:11:45 +03:00
parent bf51341750
commit 58775540aa
2 changed files with 0 additions and 105 deletions

View File

@ -1,37 +0,0 @@
%{
#include "test.tab.h"
В файле test.l есть строка:
c
Copy
#include "test.tab.h"
// Этот заголовочный файл генерируется Bison'ом и содержит:
// 2. Содержимое test.tab.h (примерно)
// typedef union {
// char *str;
// } YYSTYPE;
// extern YYSTYPE yylval;
// #define TEXT 258
// #define LBRACE 259
// #define RBRACE 260
#include <stdio.h>
#include <string.h>
void yyerror(const char *s);
%}
%%
"{" { return LBRACE; }
"}" { return RBRACE; }
[^{}]+ { // [^{}]+ = "один или больше символов, ни один из которых не является { или }"
yylval.str = strdup(yytext); // сохранение данных
return TEXT; } // возвращение типа токена
. { }
%%
int yywrap() {
return 1;
}

View File

@ -1,68 +0,0 @@
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void yyerror(const char *s) {
fprintf(stderr, "Error: %s\n", s);
}
extern int yylex();
extern FILE *yyin;
%}
// %union задаёт все возможные типы значений, которые могут быть у токенов и нетерминалов.
%union {
char *str;
}
// Этот блок в Bison (%token) определяет терминальные символы (токены),
// которые лексический анализатор (Flex) передаёт парсеру (Bison)
%token <str> TEXT // <str> — указывает, что этот токен имеет ассоциированное значение типа str (как объявлено в %union).
%token LBRACE RBRACE // LBRACE и RBRACE — это токены без ассоциированного значения. Они просто возвращают символы {,}
%%
/* правило задающее блок - структуру вида {...}, разбирается как
открывающая скобка { (LBRACE)
затем content (содержимое внутри скобок),
затем закрывающая скобка } (RBRACE).*/
block:
LBRACE content RBRACE
;
/* правило, задающее content
если контент пустой, то ничего не происходит
если контент это контент и TEXT, то освобождается память выделенная под предыдущий результат
еще контент может быть блоком
*/
content:
/* пусто */
| content TEXT { printf("TOKEN ('%s')\n", $2); free($2); }
| content block
;
%%
// 3. Как работает разбор на примере { A { B } C }
// Лексер (Flex) разбивает вход на токены:
// LBRACE ({), TEXT (A), LBRACE ({), TEXT (B), RBRACE (}), TEXT (C), RBRACE (})
// Парсер (Bison) применяет правила:
// Видит { → начинает block.
// Внутри block ожидается content.
// content может быть TEXT (A).
// Затем content может включать block ({ B }).
// Затем ещё TEXT (C).
// Закрывается } → конец block.
int main(int argc, char **argv) {
if (argc > 1) {
FILE *f = fopen(argv[1], "r");
if (!f) {
perror("Fail open file");
return 1;
}
yyin = f;
}
yyparse();
return 0;
}