From bc97a98979c3378e4f0e962b9c2667fc27239a4d Mon Sep 17 00:00:00 2001 From: Laurent Mazet Date: Sat, 24 Dec 2022 09:18:26 +0100 Subject: [PATCH] initial parser --- calc.c | 23 +++--- debug.c | 5 ++ debug.h | 21 +++++ parser.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ parser.h | 42 ++++++++++ 5 files changed, 315 insertions(+), 11 deletions(-) create mode 100644 debug.c create mode 100644 debug.h create mode 100644 parser.c create mode 100644 parser.h diff --git a/calc.c b/calc.c index 6414c2d..5c57927 100644 --- a/calc.c +++ b/calc.c @@ -1,6 +1,6 @@ /* depend: */ /* cflags: */ -/* linker: atoi.o fdprintf.o */ +/* linker: atoi.o fdprintf.o parser.o */ //#include #include @@ -8,7 +8,9 @@ #include #include "atoi.h" +#include "debug.h" #include "fdprintf.h" +#include "parser.h" /* constants */ @@ -21,15 +23,6 @@ #define MIN(x, y) (((x) < (y)) ? (x) : (y)) #define MAX(x, y) (((x) > (y)) ? (x) : (y)) -/* verbose */ - -#define ERROR 0 -#define WARNING 1 -#define INFO 2 -#define DEBUG 3 - -#define VERBOSE(level, statement...) do { if (level <= verbose) { statement; } } while(0) - /* gobal variables */ char *progname = NULL; @@ -96,14 +89,22 @@ int main (int argc, char *argv[]) while ((n = read (stdfdin, pt, BUFFER_SIZE - (pt - buffer))) != 0) { VERBOSE (DEBUG, PRINTOUT ("read %d bytes\n", n)); n += (pt - buffer); + if ((n == 2) && (buffer[0] == '.')) { + return 0; + } /* look for end of line */ for (i = 0, j = 0; i < n; i++) { if (buffer[i] == '\n') { buffer[i] = 0; VERBOSE (DEBUG, PRINTOUT ("line(%d): %s\n", j, buffer + j)); + element_t *element = parser (buffer); + if (element == (void *)(-1)) { + VERBOSE (WARNING, PRINTOUT ("error while parsing: %s\n", buffer)); + } else { + print_element (element, 0); + } //fsync (stdfdout); - fflush (stdout); j = i + 1; } } diff --git a/debug.c b/debug.c new file mode 100644 index 0000000..f2ff1ce --- /dev/null +++ b/debug.c @@ -0,0 +1,5 @@ +#include "debug.h" + +int verbose = 2; + +/* vim: set ts=4 sw=4 et */ diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..b973955 --- /dev/null +++ b/debug.h @@ -0,0 +1,21 @@ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +/* constants */ + +#define DEBUG 3 +#define INFO 2 +#define WARNING 1 +#define ERROR 0 + +/* macros */ + +#define VERBOSE(level, statement...) do { if (level <= verbose) { statement; } } while(0) + +/* gobal variables */ + +extern int verbose; + +#endif /* __DEBUG_H__ */ + +/* vim: set ts=4 sw=4 et */ diff --git a/parser.c b/parser.c new file mode 100644 index 0000000..677f9a4 --- /dev/null +++ b/parser.c @@ -0,0 +1,235 @@ +#include +#include + +#include "debug.h" +#include "fdprintf.h" + +#include "parser.h" + +/* compare codes */ + +int codecmp (char *ref, char *str) +{ + int sig; + + while (*ref != '\0') { + sig = *str++ - *ref++; + if (sig != 0) { + return (sig > 0) ? 1 : -1; + } + } + + return 0; +} + +/* allocate new element */ + +element_t *newelement (func_t function, int nbops) +{ + element_t *new = (element_t *) calloc (1, sizeof (element_t)); + if (new == NULL) { + VERBOSE (ERROR, fdprintf (stdfderr, "can't allocate memory\n")); + return NULL; + } + new->func = function; + new->nbops = nbops; + + return new; +} + +/* functions */ + +#define NB_OPERATORS 7 + +keyword_t operators[NB_OPERATORS] = { + { "+ ", Add, 2, 1 }, + { "+\t", Add, 2, 1 }, + { "- ", Sub, 2, 1 }, + { "- ", Sub, 2, 1 }, + { "*", Mul, 2, 1 }, + { "/", Div, 2, 1 }, + { "^", Pow, 2, 1 } +}; + +#define NB_FUNCTIONS 7 +keyword_t functions[NB_FUNCTIONS] = { + { "sqrt", Sqr, 1, 4 }, + { "pow", Pow, 2, 3 }, + { "cos", Cos, 1, 3 }, + { "sin", Sin, 1, 3 }, + { "atan", Atn, 1, 4 }, + { "exp", Exp, 1, 3 }, + { "log", Log, 1, 3 } +}; + +/* parser function */ + +element_t *parser (char *str) { + element_t *root = NULL; + int i; + + /* main loop */ + while (*str != '\0') { + int found = 0; + element_t *new = NULL; + VERBOSE (DEBUG, PRINTOUT ("Processing: %s\n", str)); + + /* skip spaces and tabs */ + + if ((*str == ' ') || (*str == '\t')) { + str++; + continue; + } + + /* look for operators */ + + for (i = 0; i < NB_OPERATORS; i++) { + keyword_t *operator = operators + i; + if (codecmp (operator->keyword, str) == 0) { + if ((root) && (root->func == Val)) { + VERBOSE (DEBUG, PRINTOUT ("Oper: %d\n", operator->func)); + new = newelement (operator->func, operator->nbops); + if (new == NULL) { + return (element_t *)-1; + } + new->ops[0] = root; + root = new; + } else { + return (element_t *)(-1); + } + str += operator->offset; + found = 1; + break; + } + } + if (found) { + VERBOSE (DEBUG, PRINTOUT ("stop processing operator\n")); + continue; + } + + /* look for functions */ + + for (i = 0; i < NB_FUNCTIONS; i++) { + keyword_t *function = functions + i; + if (codecmp (function->keyword, str) == 0) { + if (root == NULL) { + VERBOSE (DEBUG, PRINTOUT ("Func: %d\n", function->func)); + new = newelement (function->func, function->nbops); + if (new == NULL) { + return (element_t *)-1; + } + root = new; + } else { + return (element_t *)(-1); + } + str += function->offset; + found = 1; + break; + } + } + if (found) { + VERBOSE (DEBUG, PRINTOUT ("stop processing function\n")); + continue; + } + + /* last attend to detect addition and substraction */ + + if (((*str == '-') || (*str == '+')) && + ((*(str + 1) >= '0') && (*(str + 1) <= '9')) && + ((root) && (root->func == Val))) { + VERBOSE (DEBUG, PRINTOUT ("Oper: %d\n", Add)); + new = newelement (Add, 2); + if (new == NULL) { + return (element_t *)-1; + } + new->ops[0] = root; + root = new; + } + + /* look for number */ + + if (((*str >= '0') && (*str <= '9')) || + (*str == '.') || (*str == '-') ||(*str == '+')) { + char *pt; + float value = strtof (str, &pt); + VERBOSE (DEBUG, PRINTOUT ("Value: %f\n", value)); + if (str != pt) { + new = newelement (Val, 1); + new->value = value; + if (new == NULL) { + return (element_t *)-1; + } + if (root == NULL) { + root = new; + } else { + for (i = 0; i < root->nbops; i++) { + if (root->ops[i] == NULL) { + root->ops[i] = new; + found = 1; + break; + } + } + if (!found) { + return (element_t *)-1; + } + } + str = pt; + found = 1; + } + } + + /* error */ + + if (!found) { + return (element_t *)-1; + } + + } + + return root; +} + +/* print element tree */ + +void print_element (element_t *root, int level) +{ + char *func = NULL; + int i; + + if (root == NULL) + return; + + for (i = 0; i < level; i++) { + PRINTOUT (" "); + } + + switch (root->func) { + case Val: func = "Value"; break; + case Add: func = "Addition"; break; + case Sub: func = "Subtraction"; break; + case Mul: func = "Multiplication"; break; + case Div: func = "Division"; break; + case Pow: func = "Power"; break; + case Sqr: func = "Square Root"; break; + case Cos: func = "Cosine"; break; + case Sin: func = "Sine"; break; + case Atn: func = "Arc Tangent"; break; + case Log: func = "Logarithm"; break; + case Exp: func = "Exponantial"; break; + } + + PRINTOUT ("Function: %s\n", func); + + if (root->func == Val) { + for (i = 0; i < level; i++) { + PRINTOUT (" "); + } + PRINTOUT ("value: %f\n", root->value); + } else { + for (i = 0; i < root->nbops; i++) { + print_element (root->ops[i], level + 1); + } + } +} + +/* vim: set ts=4 sw=4 et: */ diff --git a/parser.h b/parser.h new file mode 100644 index 0000000..4650007 --- /dev/null +++ b/parser.h @@ -0,0 +1,42 @@ +#ifndef __PARSER_H__ +#define __PARSER_H__ + +/* function type */ + +typedef enum { + Val = 0, + Add, Sub, + Mul, Div, Pow, + Sqr, + Cos, Sin, Atn, + Log, Exp +} func_t; + +/* keyword type */ + +typedef struct _keyword_t { + char *keyword; + func_t func; + int nbops; + int offset; +} keyword_t; + +/* calculus element type */ + +#define MAX_OPERANDS 2 +typedef struct _element_t { + func_t func; + int nbops; + struct _element_t *ops[MAX_OPERANDS]; + float value; +} element_t; + +/* parser function */ + +element_t *parser (char *str); + +void print_element (element_t *root, int level); + +#endif /* __PARSER_H__ */ + +/* vim: set ts=4 sw=4 et: */ -- 2.30.2