block parse added
parent
57bc30a39c
commit
f5a2854934
|
@ -0,0 +1,22 @@
|
|||
%{
|
||||
#include "test.tab.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int yylineno;
|
||||
|
||||
%}
|
||||
|
||||
%%
|
||||
"{" { return LBRACE; }
|
||||
"}" { return RBRACE; }
|
||||
\n { yylineno++; }
|
||||
[^{}]+ {
|
||||
yylval.str = strdup(yytext);
|
||||
return TEXT;
|
||||
}
|
||||
%%
|
||||
|
||||
int yywrap() {
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
%{
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
extern int yylineno;
|
||||
extern char *yytext;
|
||||
|
||||
void yyerror(const char *s) {
|
||||
fprintf(stderr, "\033[91mError at line %i\033[0m", yylineno);
|
||||
exit(1);
|
||||
}
|
||||
extern int yylex();
|
||||
extern FILE *yyin;
|
||||
%}
|
||||
|
||||
%union {
|
||||
char *str;
|
||||
}
|
||||
|
||||
%token <str> TEXT
|
||||
%token LBRACE RBRACE
|
||||
|
||||
%%
|
||||
|
||||
block:
|
||||
LBRACE content RBRACE
|
||||
;
|
||||
|
||||
content:
|
||||
| content TEXT { printf("TOKEN ('%s')\n", $2); free($2); }
|
||||
| content block {}
|
||||
;
|
||||
%%
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
yylineno = 1;
|
||||
|
||||
if (argc > 1) {
|
||||
FILE *f = fopen(argv[1], "r");
|
||||
if (!f) {
|
||||
perror("\033[91mFail open file\033[0m");
|
||||
return 1;
|
||||
}
|
||||
yyin = f;
|
||||
}
|
||||
yyparse();
|
||||
return 0;
|
||||
}
|
2
main.py
2
main.py
|
@ -3,7 +3,7 @@ import subprocess
|
|||
|
||||
# ЭТИ ПУТИ НАДО ЗАДАТЬ ВРУЧНУЮ
|
||||
# *.l и *.y файлы из директории ANALYZERS_DIR ДОЛЖНЫ НАЗЫВАТЬСЯ как basename этой директории!!!
|
||||
ANALYZERS_DIR = r'C:\Users\user\Desktop\УЧЕБА\6_СЕМ\КОМПИЛЯТОРЫ\flex_bison_test\analyzers\cpl'
|
||||
ANALYZERS_DIR = r'C:\Users\user\Desktop\УЧЕБА\6_СЕМ\КОМПИЛЯТОРЫ\flex_bison_test\analyzers\test'
|
||||
FLEX_EXE_PATH = r"C:\tools\win_flex_bison\win_flex.exe"
|
||||
BISON_EXE_PATH = r"C:\tools\win_flex_bison\win_bison.exe"
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
{ 1 231233
|
||||
{1}{}
|
||||
block1 {
|
||||
block2 { block3 }
|
||||
block4 asjdb asd bajds ba
|
||||
} 126316
|
||||
block5
|
||||
}
|
||||
{
|
||||
123
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
%{
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
%{
|
||||
#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