tutorial del
parent
bf51341750
commit
58775540aa
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
Loading…
Reference in New Issue