diff --git a/analyzers/c_analyzer/c_analyzer.l b/analyzers/c_analyzer/c_analyzer.l new file mode 100644 index 0000000..5b6001f --- /dev/null +++ b/analyzers/c_analyzer/c_analyzer.l @@ -0,0 +1,36 @@ +%{ +#include "c_analyzer.tab.h" +#include +#include +#include + +int line_number = 1; + +void yyerror(const char *s) { + fprintf(stderr, "\033[91mError at line %i: %s near '%s'\033[0m\n", line_number, s, yytext); + exit(1); +} + +%} + +%% +"{" { return LBRACE; } +"}" { return RBRACE; } +";" { return SEMICOLON; } +"=" { return ASSIGN; } +"+" { return PLUS; } +"-" { return MINUS; } +"*" { return MULT; } +"/" { return DIV; } +"return" { return RET; } +"print" { return PRINT; } +[0-9]+ { yylval.str = strdup(yytext); return NUMBER; } +[a-zA-Z_][a-zA-Z0-9_]* { yylval.str = strdup(yytext); return IDENTIFIER; } +[ \t] ; +\n { line_number++; } +. { yyerror("Invalid character"); } +%% + +int yywrap() { + return 1; +} \ No newline at end of file diff --git a/analyzers/c_analyzer/c_analyzer.y b/analyzers/c_analyzer/c_analyzer.y new file mode 100644 index 0000000..2dfbf90 --- /dev/null +++ b/analyzers/c_analyzer/c_analyzer.y @@ -0,0 +1,67 @@ +%{ +#include +#include +#include + +extern char *yytext; + +void yyerror(const char *s); +extern int yylex(); +extern FILE *yyin; +%} + +%union { + char *str; +} + +%token IDENTIFIER NUMBER RET PRINT +%token LBRACE RBRACE SEMICOLON ASSIGN PLUS MINUS MULT DIV + +%type expr program statement block + +%% + +// Program - последовательность утверждений +program: + | program statement + ; + +// Утверждение - либо блок {...}, либо выражение с ; в конце +statement: + expr SEMICOLON + | block + ; + +// Блок - { program }, т.е. это последовательность утверждений и она находится в скобках { } +block: + LBRACE program RBRACE + ; + +// Возможные выражения +expr: + RET expr // выражение вида return expr + | PRINT expr // выражение вида print expr + | IDENTIFIER ASSIGN expr // выражения вида a=expr + | expr PLUS expr // выражения вида expr+expr + | expr MINUS expr // выражения вида expr-expr + | expr MULT expr // выражения вида expr*expr + | expr DIV expr // выражения вида expr/expr + | IDENTIFIER { printf("IDENTIFIER = %s\n", $1); free($1); } + | NUMBER { printf("NUMBER = %s\n", $1); free($1); } + ; + +%% + +int main(int argc, char **argv) { + if (argc > 1) { + FILE *f = fopen(argv[1], "r"); + if (!f) { + perror("\033[91mFail open file\033[0m"); + return 1; + } + yyin = f; + } + yyparse(); + printf("\033[92mSuccess parsed!\033[0m"); + return 0; +} \ No newline at end of file diff --git a/analyzers/cpl/cpl.l b/analyzers/cpl/cpl.l deleted file mode 100644 index ddd8c9a..0000000 --- a/analyzers/cpl/cpl.l +++ /dev/null @@ -1,52 +0,0 @@ -%{ -#include "cpl.tab.h" -#include -#include -#include - -extern int yylineno; -char *last_lexeme; // Глобальная переменная для хранения текущей лексемы -void yyerror(const char *s); -%} - -%option noyywrap - -DIGIT [0-9] -ID [a-zA-Z][a-zA-Z0-9_]* -WS [ \t]+ - -%% - -"if" { last_lexeme = strdup("if"); return IF; } -"else" { last_lexeme = strdup("else"); return ELSE; } -"while" { last_lexeme = strdup("while"); return WHILE; } -"return" { last_lexeme = strdup("return"); return RETURN; } -"print" { last_lexeme = strdup("print"); return PRINT; } -"&&" { last_lexeme = strdup("&&"); return AND; } -"||" { last_lexeme = strdup("||"); return OR; } -"!" { last_lexeme = strdup("!"); return NOT; } -">=" { last_lexeme = strdup(">="); return GE; } -"<=" { last_lexeme = strdup("<="); return LE; } -"==" { last_lexeme = strdup("=="); return EQ; } -"!=" { last_lexeme = strdup("!="); return NE; } -">" { last_lexeme = strdup(">"); return '>'; } -"<" { last_lexeme = strdup("<"); return '<'; } -"+" { last_lexeme = strdup("+"); return '+'; } -"-" { last_lexeme = strdup("-"); return '-'; } -"*" { last_lexeme = strdup("*"); return '*'; } -"/" { last_lexeme = strdup("/"); return '/'; } -"%" { last_lexeme = strdup("%"); return '%'; } -"(" { last_lexeme = strdup("("); return '('; } -")" { last_lexeme = strdup(")"); return ')'; } -";" { last_lexeme = strdup(";"); return ';'; } -"=" { last_lexeme = strdup("="); return '='; } -"{" { last_lexeme = strdup("{"); return '{'; } -"}" { last_lexeme = strdup("}"); return '}'; } - -{DIGIT}+ { last_lexeme = strdup(yytext); yylval.num = atoi(yytext); return NUMBER; } -{ID} { last_lexeme = strdup(yytext); yylval.str = strdup(yytext); return IDENTIFIER; } -{WS} /* skip whitespace */ -\n { yylineno++; } -. { last_lexeme = strdup(yytext); yyerror("invalid character"); } - -%% \ No newline at end of file diff --git a/analyzers/cpl/cpl.y b/analyzers/cpl/cpl.y deleted file mode 100644 index 3f828b5..0000000 --- a/analyzers/cpl/cpl.y +++ /dev/null @@ -1,106 +0,0 @@ -%{ -#include -#include -#include - -extern int yylineno; -extern char *last_lexeme; -void yyerror(const char *s); -int yylex(); - -extern FILE *yyin; -%} - -%union { - int num; - char *str; -} - -%token NUMBER -%token IDENTIFIER -%token IF ELSE WHILE RETURN PRINT -%token AND OR NOT GE LE EQ NE - -%right '=' -%left OR -%left AND -%left EQ NE -%left '<' '>' GE LE -%left '+' '-' -%left '*' '/' '%' -%right NOT UMINUS - -%% - -program: - | program statement - ; - -statement: - expr ';' semicolons - | IF '(' expr ')' statement ELSE statement - | IF '(' expr ')' statement - | WHILE '(' expr ')' statement - | RETURN expr ';' semicolons - | PRINT expr ';' semicolons - | '{' program '}' - ; - -semicolons: - /* empty */ - | semicolons ';' - ; - -expr: - NUMBER - | IDENTIFIER - | IDENTIFIER '=' expr - | expr '+' expr - | expr '-' expr - | expr '*' expr - | expr '/' expr - | expr '%' expr - | expr AND expr - | expr OR expr - | NOT expr - | '-' expr %prec UMINUS - | '+' expr - | expr '>' expr - | expr '<' expr - | expr GE expr - | expr LE expr - | expr EQ expr - | expr NE expr - | '(' expr ')' - ; - -%% - -void yyerror(const char *s) { - if (last_lexeme) { - fprintf(stderr, "\033[91mError at line %d: %s (near '%s')\n\033[0m", yylineno, s, last_lexeme); - } else { - fprintf(stderr, "\033[91mError at line %d: %s\n\033[0m", yylineno, s); - } - exit(1); -} - -int main(int argc, char *argv[]) { - if (argc < 2) { - fprintf(stderr, "\033[91mUsage: %s \n\033[0m", argv[0]); - return 1; - } - - FILE *input = fopen(argv[1], "r"); - if (!input) { - perror("\033[91mError opening file"); printf("\033[0m"); - return 1; - } - - yyin = input; - yyparse(); - fclose(input); - - printf("\033[92mParsing completed successfully!\033[0m\n"); - return 0; -} \ No newline at end of file diff --git a/analyzers/cpl/test.cpl b/analyzers/cpl/test.cpl deleted file mode 100644 index 8aa38a1..0000000 --- a/analyzers/cpl/test.cpl +++ /dev/null @@ -1,22 +0,0 @@ -{ - PIMPUMPUMpam = 5; - per__emennaya = 3; - - PIMPUMPUMpam = PIMPUMPUMpam + (per__emennaya - 1); - - x = 10+1-2;;;; - y = ++-+20; - - if (++---x > y) { - print x * !x; - } else { - print y; - } - - while (x > 123 || (x < 1 || x > 10) && x == 5) { - {x = x + 1;} - x = x % 3; - } - - return 0; -} \ No newline at end of file diff --git a/code.txt b/code.txt new file mode 100644 index 0000000..5461d51 --- /dev/null +++ b/code.txt @@ -0,0 +1,13 @@ +{ + x = 2 + 1; + x = z + 3 + 5; + { + x = 10; + y = x + 5; + { + z = y * 2 / 5 * 3; + } + } + print x; + return x / 2 + 5; +} \ No newline at end of file diff --git a/main.py b/main.py index c90ac86..9ad27ae 100644 --- a/main.py +++ b/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\test' +ANALYZERS_DIR = r'C:\Users\user\Desktop\УЧЕБА\6_СЕМ\КОМПИЛЯТОРЫ\flex_bison_test\analyzers\c_analyzer' FLEX_EXE_PATH = r"C:\tools\win_flex_bison\win_flex.exe" BISON_EXE_PATH = r"C:\tools\win_flex_bison\win_bison.exe" @@ -35,7 +35,6 @@ def main(): except subprocess.CalledProcessError as e: print("\033[91mErrors:\033[0m") print(e.stderr) - return # Очистка промежуточных файлов (только если все команды успешны) for path in ['lex.yy.c', f'{analyzer_name}.tab.c', f'{analyzer_name}.tab.h']: