From 6d5f42daf7437f0190a5a2b06680d2491ef237f6 Mon Sep 17 00:00:00 2001 From: Pedro Date: Thu, 16 Oct 2014 15:30:59 +0200 Subject: [PATCH] added a working thread-safe lemon example --- lemon_example/.gitignore | 5 +++ lemon_example/build_and_run.sh | 9 +++++ lemon_example/flex_scanner.l | 17 +++++++++ lemon_example/lemon_parser.y | 23 ++++++++++++ lemon_example/main.cpp | 65 ++++++++++++++++++++++++++++++++++ 5 files changed, 119 insertions(+) create mode 100644 lemon_example/.gitignore create mode 100644 lemon_example/build_and_run.sh create mode 100644 lemon_example/flex_scanner.l create mode 100644 lemon_example/lemon_parser.y create mode 100644 lemon_example/main.cpp diff --git a/lemon_example/.gitignore b/lemon_example/.gitignore new file mode 100644 index 0000000..cc6294c --- /dev/null +++ b/lemon_example/.gitignore @@ -0,0 +1,5 @@ +flex_scanner.h +flex_scanner.c +lemon_parser.h +lemon_parser.c +lemon_test \ No newline at end of file diff --git a/lemon_example/build_and_run.sh b/lemon_example/build_and_run.sh new file mode 100644 index 0000000..57bcabe --- /dev/null +++ b/lemon_example/build_and_run.sh @@ -0,0 +1,9 @@ +rm -f lemon_test lemon_parser.c flex_scanner.c +echo "Lemon" +lemon lemon_parser.y +echo "Flex" +# flex lexer.l +flex --outfile=flex_scanner.c --header-file=flex_scanner.h flex_scanner.l +echo "Compile" +g++ main.cpp lemon_parser.c flex_scanner.c -o lemon_test -std=c++11 -pthread +./lemon_test \ No newline at end of file diff --git a/lemon_example/flex_scanner.l b/lemon_example/flex_scanner.l new file mode 100644 index 0000000..c47c4ff --- /dev/null +++ b/lemon_example/flex_scanner.l @@ -0,0 +1,17 @@ +%{ + #include "lemon_parser.h" + #include +%} + + +%option reentrant +%option noyywrap + + +%% +[0-9]+|[0-9]+.[0-9]+ return NUMBER; +[+] return PLUS; +[\n] return NL; +[ \t] ; /* skip whitespace */ +. {printf("Unknown character '%c'\n", yytext[0]); return 0;} +%% diff --git a/lemon_example/lemon_parser.y b/lemon_example/lemon_parser.y new file mode 100644 index 0000000..f811734 --- /dev/null +++ b/lemon_example/lemon_parser.y @@ -0,0 +1,23 @@ +%include { + #include + #include +} +%syntax_error { printf("Lemon syntax error\n"); } + +%token_type {const char*} +%type expr {float} + +%left PLUS MINUS . + +%extra_argument { float* result } + +start ::= prog. + +prog ::= prog print NL . +prog ::= prog print . +prog ::= . + +print ::= expr(a) . { *result = a; } + +expr(a) ::= NUMBER(b) . { a = atof(b); } +expr(a) ::= expr(b) PLUS expr(c) . { a = b + c; } \ No newline at end of file diff --git a/lemon_example/main.cpp b/lemon_example/main.cpp new file mode 100644 index 0000000..069310f --- /dev/null +++ b/lemon_example/main.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include "flex_scanner.h" +#include "lemon_parser.h" + +// Based on https://github.com/theory/flex-lemon-example +// and http://stackoverflow.com/questions/24833465/bison-yacc-vs-lemon-vs-standard-input +typedef float ResultType; + +void *ParseAlloc(void *(*mallocProc)(size_t)); +void ParseFree(void *p, void (*freeProc)(void*)); +void Parse(void *yyp, int yymajor, const char* text, ResultType*); + +int yylex(void); +int yylval; + + +float parseString(const char* string) { + yyscan_t scanner; + yylex_init(&scanner); + + // Scan the provided string + YY_BUFFER_STATE state = yy_scan_string(string, scanner); + + void* lemonParser = ParseAlloc(malloc); + int tokenCode; + ResultType result; + do { + tokenCode = yylex(scanner); + Parse(lemonParser, tokenCode, yyget_text(scanner), &result); + // printf("Token %d\n", tokenCode); + } while (tokenCode > 0); + + return result; +} + + +void multithreadTest(int numOfParses, int id) { + for (int n = 0; n < numOfParses; ++n) { + int a = rand() % 1000 + 1; + int b = rand() % 1000 + 1; + int c = a + b; + char string[32]; + sprintf(string, "%d + %d", a, b); + + int result = parseString(string); + if (result != c) printf("Error[%d]! %s != %d\n", id, string, result); + } +} + +int main(void) { + const int numThreads = 10; + int numRuns = 5000; + + std::thread threads[numThreads]; + for (int n = 0; n < numThreads; ++n) { + threads[n] = std::thread(multithreadTest, numRuns, n); + } + + for (int n = 0; n < numThreads; ++n) { + threads[n].join(); + } + return 0; +} \ No newline at end of file