diff options
author | Oxore <oxore@protonmail.com> | 2025-01-04 22:56:24 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2025-01-04 22:58:43 +0300 |
commit | ca8f17077af731cea01234530bf8c528481c7876 (patch) | |
tree | daf214bb4df75d3339c6c8b7255544e49aa49154 |
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Readme.md | 3 | ||||
-rw-r--r-- | simple-c/CMakeLists.txt | 38 | ||||
-rw-r--r-- | simple-c/lexer.l | 37 | ||||
-rw-r--r-- | simple-c/parser.y | 75 |
5 files changed, 154 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..69a3537 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +cmake[-_]build/ diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..4076b35 --- /dev/null +++ b/Readme.md @@ -0,0 +1,3 @@ +# Flex + Bison examples + +Based on https://github.com/sunxfancy/flex-bison-examples/tree/master diff --git a/simple-c/CMakeLists.txt b/simple-c/CMakeLists.txt new file mode 100644 index 0000000..db41628 --- /dev/null +++ b/simple-c/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.20) +project("simple-c") + +find_package(BISON REQUIRED) +find_package(FLEX REQUIRED) + +if (WIN32) + set (ADDITIONAL_FLEX_FLAGS "--wincompat") +else() + set (ADDITIONAL_FLEX_FLAGS "") +endif() + +flex_target(lexer + lexer.l + ${CMAKE_CURRENT_BINARY_DIR}/lexer.c + DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/lexer.h + COMPILE_FLAGS ${ADDITIONAL_FLEX_FLAGS} +) + +bison_target(parser + parser.y + ${CMAKE_CURRENT_BINARY_DIR}/parser.c + COMPILE_FLAGS "-d -v" +) + +add_flex_bison_dependency(lexer parser) + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) + +set(source_files + ${CMAKE_CURRENT_BINARY_DIR}/parser.c + ${CMAKE_CURRENT_BINARY_DIR}/lexer.c +) + +add_executable(${PROJECT_NAME} ${source_files} ${BISON_PARSER_OUTPUTS} ${FLEX_LEXER_OUTPUTS}) diff --git a/simple-c/lexer.l b/simple-c/lexer.l new file mode 100644 index 0000000..be983d1 --- /dev/null +++ b/simple-c/lexer.l @@ -0,0 +1,37 @@ +%{ +#include "parser.h" +#define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno; +%} + +%option noyywrap + +DIGIT [0-9] + +%% + +"-" { return MINUS; } +"+" { return PLUS; } +"*" { return MULT; } +"/" { return DIV; } +"=" { return EQUAL; } +"(" { return L_PAREN; } +")" { return R_PAREN; } + +(\.{DIGIT}+)|({DIGIT}+(\.{DIGIT}*)?([eE][+-]?[0-9]+)?) { + yylval.dval = atof(yytext); + return NUMBER; +} + +[ \t]+ { /* ignore spaces */ } + +"\n" { return END; } + +. { + printf( + "Error at line %d: unrecognized symbol \"%s\"\n", + yylloc.first_line, + yytext); + exit(0); +} + +%% diff --git a/simple-c/parser.y b/simple-c/parser.y new file mode 100644 index 0000000..ac61b8b --- /dev/null +++ b/simple-c/parser.y @@ -0,0 +1,75 @@ +/* calculator. */ +%{ + +#include <stdio.h> +#include <stdlib.h> +#include "lexer.h" + +void yyerror(const char *msg); + +// Here is an example how to create custom data structure +typedef struct custom_data { + char* name; + int counter; +} custom_data; + +%} + +%union{ + double dval; + int ival; + struct custom_data* cval; // define the pointer type for custom data structure +} + +%define parse.error verbose +%locations + +%start input +%token MULT DIV PLUS MINUS EQUAL L_PAREN R_PAREN END +%token <dval> NUMBER +%type <dval> exp +%type <cval> input +%left PLUS MINUS +%left MULT DIV +%nonassoc UMINUS + +%% + +input: { + $$ = malloc(sizeof(custom_data)); $$->name = "input"; $$->counter = 0; +} +| input line { + $$ = $1; $1->counter++; +} +; + +line: exp EQUAL END { printf("\t%f\n", $1); }; + +exp: NUMBER { $$ = $1; } +| exp PLUS exp { $$ = $1 + $3; } +| exp MINUS exp { $$ = $1 - $3; } +| exp MULT exp { $$ = $1 * $3; } +| exp DIV exp { + if ($3==0) yyerror("divide by zero"); else $$ = $1 / $3; +} +| MINUS exp %prec UMINUS { $$ = -$2; } +| L_PAREN exp R_PAREN { $$ = $2; } +; +%% + +int main(int argc, char **argv) +{ + if (argc > 1) { + yyin = fopen(argv[1], "r"); + if (yyin == NULL){ + printf("syntax: %s filename\n", argv[0]); + } + } + yyparse(); // Calls yylex() for tokens. + return 0; +} + +void yyerror(const char *msg) +{ + printf("** Line %d: %s\n", yylloc.first_line, msg); +} |