├── testfile ├── README ├── Makefile ├── parser.y ├── LICENSE.txt └── lexer.rl /testfile: -------------------------------------------------------------------------------- 1 | (1.25 + 2.5) / (0.125 * 2.0); 2 | 1.5 - 2.2; 3 | 4 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is a simple, ragel, lemon based calculator. 2 | Basically, just shows how to glue ragel and lemon together to 3 | make a relatively simple lexer/parser pair. 4 | 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | calc: lexer.o 2 | g++ lexer.o -o calc 3 | 4 | parser.c: parser.y 5 | lemon parser.y 6 | 7 | parser.h: parser.y 8 | lemon parser.y 9 | 10 | lexer.cpp: lexer.rl parser.h parser.c 11 | ragel lexer.rl -o lexer.cpp 12 | 13 | lexer.o: lexer.cpp 14 | g++ -c lexer.cpp 15 | 16 | clean: 17 | rm -f *.o lexer.cpp parser.h parser.c parser.out calc 18 | 19 | -------------------------------------------------------------------------------- /parser.y: -------------------------------------------------------------------------------- 1 | %token_type {double} 2 | 3 | %left PLUS MINUS. 4 | %left DIVIDE TIMES. 5 | 6 | %include { 7 | #include 8 | #include 9 | #include "parser.h" 10 | } 11 | 12 | %syntax_error { 13 | std::cout << "Syntax error." << std::endl; 14 | } 15 | 16 | program ::= expr(A). { std::cout << A << std::endl; } 17 | 18 | expr(A) ::= OPENP expr(B) CLOSEP. { A = (B); } 19 | expr(A) ::= expr(B) PLUS expr(C). { A = B + C; } 20 | expr(A) ::= expr(B) DIVIDE expr(C). { A = B / C; } 21 | expr(A) ::= expr(B) TIMES expr(C). { A = B * C; } 22 | expr(A) ::= expr(B) MINUS expr(C). { A = B - C; } 23 | expr(A) ::= DOUBLE(B). { A = B; } 24 | 25 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Peter Couperus 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | -------------------------------------------------------------------------------- /lexer.rl: -------------------------------------------------------------------------------- 1 | //This is just a sketch on how to make a simple calculator. 2 | // Reads in a file, and outputs the result of each calculation. 3 | 4 | #include 5 | #include 6 | #include 7 | #include "parser.c" 8 | 9 | std::string getStr(const char* beg, const char* end) 10 | { 11 | return std::string(beg).substr(0, end-beg); 12 | } 13 | 14 | 15 | %%{ 16 | 17 | machine calc; 18 | 19 | action semi_tok { 20 | //Terminate this calculation. 21 | Parse(lparser, 0, 0); 22 | } 23 | 24 | action plus_tok { 25 | Parse(lparser, PLUS, 0); 26 | } 27 | 28 | action minus_tok { 29 | Parse(lparser, MINUS, 0); 30 | } 31 | 32 | action times_tok { 33 | Parse(lparser, TIMES, 0); 34 | } 35 | 36 | action divide_tok { 37 | Parse(lparser, DIVIDE, 0); 38 | } 39 | 40 | action openp_tok { 41 | Parse(lparser, OPENP, 0); 42 | } 43 | 44 | action closep_tok { 45 | Parse(lparser, CLOSEP, 0); 46 | } 47 | 48 | action number_tok{ 49 | Parse(lparser, DOUBLE, atof(getStr(ts, te).c_str())); 50 | } 51 | 52 | number = [0-9]+('.'[0-9]+)?; 53 | plus = '+'; 54 | minus = '-'; 55 | openp = '('; 56 | closep = ')'; 57 | times = '*'; 58 | divide = '/'; 59 | semi = ';'; 60 | 61 | main := |* 62 | number => number_tok; 63 | plus => plus_tok; 64 | minus => minus_tok; 65 | openp => openp_tok; 66 | closep => closep_tok; 67 | times => times_tok; 68 | divide => divide_tok; 69 | semi => semi_tok; 70 | space; 71 | *|; 72 | 73 | }%% 74 | 75 | %% write data; 76 | 77 | class Scan 78 | { 79 | public: 80 | ~Scan(); 81 | void init(); 82 | void execute(const char* data, size_t len); 83 | 84 | 85 | private: 86 | int cs; 87 | int act; 88 | const char* ts; 89 | const char* te; 90 | 91 | void* lparser; 92 | }; 93 | 94 | Scan::~Scan() 95 | { 96 | ParseFree(lparser, free); 97 | } 98 | 99 | void 100 | Scan::init() 101 | { 102 | lparser = ParseAlloc(malloc); 103 | 104 | %% write init; 105 | } 106 | 107 | void 108 | Scan::execute(const char* data, size_t len) 109 | { 110 | const char* p = data; 111 | const char* pe = data + len; 112 | const char* eof = pe; 113 | 114 | %% write exec; 115 | } 116 | 117 | int main(int argc, char **argv) 118 | { 119 | char buffer[4096]; 120 | FILE* f; 121 | Scan scan; 122 | long numbytes; 123 | 124 | //Read the whole file into the buffer. 125 | f = fopen(argv[1], "r"); 126 | fseek(f, 0, SEEK_END); 127 | numbytes = ftell(f); 128 | fseek(f, 0, SEEK_SET); 129 | fread(buffer, 1, numbytes, f); 130 | 131 | //Parse the buffer in one fell swoop. 132 | scan.init(); 133 | scan.execute(buffer, numbytes); 134 | return 0; 135 | } 136 | 137 | --------------------------------------------------------------------------------