summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2025-01-04 22:56:24 +0300
committerOxore <oxore@protonmail.com>2025-01-04 22:58:43 +0300
commitca8f17077af731cea01234530bf8c528481c7876 (patch)
treedaf214bb4df75d3339c6c8b7255544e49aa49154
Initial commitHEADmaster
-rw-r--r--.gitignore1
-rw-r--r--Readme.md3
-rw-r--r--simple-c/CMakeLists.txt38
-rw-r--r--simple-c/lexer.l37
-rw-r--r--simple-c/parser.y75
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);
+}