diff --git a/ast-lex-yacc/.gitignore b/ast-lex-yacc/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/ast-lex-yacc/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/ast-lex-yacc/Makefile b/ast-lex-yacc/Makefile index 7cdc77b..33b722a 100644 --- a/ast-lex-yacc/Makefile +++ b/ast-lex-yacc/Makefile @@ -1,6 +1,8 @@ BUILDDIR = build -TARGET_SRC = main +OUT = main +SRC_DIR = src +INCLUDE_DIR = inc build: mkdir main all: mkdir main run @@ -12,15 +14,15 @@ run: # run binary ./$(BUILDDIR)/main main: lex.yy.c yacc.yy.c - cc $(BUILDDIR)/yacc.yy.c $(BUILDDIR)/lex.yy.c -o $(BUILDDIR)/$(TARGET_SRC) -lfl + cc -Wall -I$(INCLUDE_DIR) $(SRC_DIR)/extio.c $(BUILDDIR)/yacc.yy.c $(BUILDDIR)/lex.yy.c -o $(BUILDDIR)/$(OUT) # generate c file for lex lex.yy.c: - flex -o $(BUILDDIR)/lex.yy.c $(TARGET_SRC).l + flex -o $(BUILDDIR)/lex.yy.c $(SRC_DIR)/lexer.l # generate c file for yacc yacc.yy.c: - yacc -d -o $(BUILDDIR)/yacc.yy.c $(TARGET_SRC).y + yacc -d -o $(BUILDDIR)/yacc.yy.c $(SRC_DIR)/parser.y clean: # wipe the build directory rm -f $(BUILDDIR)/* diff --git a/ast-lex-yacc/inc/extio.h b/ast-lex-yacc/inc/extio.h new file mode 100644 index 0000000..88d6722 --- /dev/null +++ b/ast-lex-yacc/inc/extio.h @@ -0,0 +1,18 @@ +#ifndef _EXTIO_H_ +#define _EXTIO_H_ + +#include +#include + +// define different ANSI format strings +extern const char *DEBUG; +extern const char *INFO; +extern const char *WARN; +extern const char *ERROR; + +/** + * prints a notification string to standard out + */ +int notify(const char *type, const char *format, ...); + +#endif diff --git a/ast-lex-yacc/main.l b/ast-lex-yacc/main.l deleted file mode 100644 index 0f0acfe..0000000 --- a/ast-lex-yacc/main.l +++ /dev/null @@ -1,37 +0,0 @@ -%option noyywrap -%{ - #include - #include "yacc.yy.h" - #define YYDEBUG 1 - int yyLineNumber = 1; -%} - -%% -\n yyLineNumber++; -0|[1-9][0-9]* return(Number); // integer numbers -"VAR"|"var" return(Variable); -"INT"|"int" return(Integer); -[a-zA-Z]+ return(Ident); -"," return(','); -":" return(':'); -";" return(';'); -"+" return('+'); -"-" return('-'); -"(" return('('); -")" return(')'); -[ \t] -. print_stdout("unknown Symbol"); -%% - -/* -int main() -{ - printf("Programm eingeben: \n"); - yylex(); - return 0; -} -*/ - -int print_stdout(char token[]) { - printf("\nFLEX/[INF] >>> Token (%d) AS %s ```%s```\n", yyLineNumber, token, yytext); -} diff --git a/ast-lex-yacc/main.y b/ast-lex-yacc/main.y deleted file mode 100644 index db701c0..0000000 --- a/ast-lex-yacc/main.y +++ /dev/null @@ -1,28 +0,0 @@ -%{ - #include - extern int yylineno; -%} - -%token Variable -%token Integer -%token Ident -%token Number - -%% -program: decllist exprlist; -decllist: decl ';' | decllist decl ';' | /* empty */ | error ';' { yyerror(" im Deklarationsteil\n"); }; -decl: Variable idlist ':' type; -idlist: Ident | idlist ',' Ident; -type: Integer; -exprlist: /* empty */ ; -%% - -int main() { - printf("Bitte geben Sie ein Program ein: \n"); - yyparse(); - return 0; -} - -int yyerror(char *s) { - printf("YACC/[ERR] >>> Failed parsing grammar (%d): ```%s```", yylineno, s); -} diff --git a/ast-lex-yacc/src/extio.c b/ast-lex-yacc/src/extio.c new file mode 100644 index 0000000..cbc15c9 --- /dev/null +++ b/ast-lex-yacc/src/extio.c @@ -0,0 +1,49 @@ +#include "extio.h" + +#define COLORS + +extern int yylineno; + +#ifdef COLORS + +#define NORMAL "\x1b[0m" +#define GREEN "\33[32m" +#define RED "\33[31m" +#define YELLOW "\33[33m" +#define BLUE "\33[34m" +#define BOLD "\033[1m" + +#else + +#define NORMAL "" +#define GREEN "" +#define RED "" +#define YELLOW "" +#define BLUE "" +#define BOLD "" + +#endif + +// define different ANSI format strings +const char *DEBUG = GREEN "DEBUG" NORMAL; +const char *INFO = BLUE "INFO" NORMAL; +const char *WARN = BOLD "" YELLOW "WARNING" NORMAL; +const char *ERROR = RED "ERROR" NORMAL; + +int notify(const char *type, const char *format, ...) { + int char_count = 0; + + // print header + char_count += printf("%s in line %d: " BOLD, type, yylineno); + + // print formatted variable arguments + va_list args; + va_start(args, format); + char_count += vprintf(format, args); + va_end(args); + + // print tail + char_count += printf(NORMAL "\n\torigin: YACC type: SYNTAX\n\n"); + + return char_count; +} diff --git a/ast-lex-yacc/src/lexer.l b/ast-lex-yacc/src/lexer.l new file mode 100644 index 0000000..e640009 --- /dev/null +++ b/ast-lex-yacc/src/lexer.l @@ -0,0 +1,30 @@ +%option noyywrap +%{ + #include + #include + #include "yacc.yy.h" + #include "extio.h" + + int yyLineNumber = 1; + int yylex(); +%} + +%% +\n yyLineNumber++; +0|[1-9][0-9]* { yylval.num = atoi(yytext); return(Number); } // integer numbers +"VAR"|"var" return(Variable); +"INT"|"int" return(Integer); +[a-zA-Z]+ { yylval.str = strdup(yytext); return(Ident); }; // FIXME: unfreed heap allocation +"," return(','); +":" return(':'); +";" return(';'); +"+" return(Operator); +"-" return(Operator); +"*" return(Operator); +"/" return(Operator); +"(" return('('); +")" return(')'); +[ \t] +. notify(WARN, "unknown Symbol: %s", yytext); +%% + diff --git a/ast-lex-yacc/src/parser.y b/ast-lex-yacc/src/parser.y new file mode 100644 index 0000000..725c475 --- /dev/null +++ b/ast-lex-yacc/src/parser.y @@ -0,0 +1,61 @@ +%{ + #define COLORS + + #include + #include "extio.h" + extern int yylineno; + + int yyerror(char*); + int yylex(); +%} + +%union { + char *str; + int num; +} + +%token Variable +%token Integer +%token Ident +%token Number +%token Operator + +%% +program: decllist exprlist; + +decllist: decl ';' + | decllist decl ';' + | /* empty */ | + error ';' { notify(ERROR, "in declaration"); }; + +decl: Variable idlist ':' type { notify(DEBUG, "declaration found"); }; + +idlist: Ident { notify(DEBUG, "identifier found"); }; + | idlist ',' Ident; + +type: Integer { notify(DEBUG, "type found"); }; + +exprlist: expr ';' { notify(DEBUG, "expression discovered"); } + | exprlist expr ';'; + +expr: '(' expr Operator expr ')' + | error expr Operator expr ')' { notify(ERROR, "missing open parenthesis"); } + | '(' error Operator expr ')' { notify(ERROR, "error in left hand expression"); } + | '(' expr error expr ')' { notify(ERROR, "expected operator in expression"); } + | '(' expr Operator error ')' { notify(ERROR, "error in right hand expression"); } + | '(' expr Operator expr error { notify(ERROR, "missing closing parenthesis"); } + | Ident { notify(DEBUG, "identifier: %s", $1); } + | Number { notify(DEBUG, "number: %08x", yyval.num); } + | error ';' { notify(ERROR, "in expression"); }; +%% + +int main() { + printf("Bitte geben Sie ein Program ein: \n"); + yyparse(); + return 0; +} + +int yyerror(char *s) { + return 0; +} +