simple calculator using a scanner (re2c) and a parser generator (lemon)

Reply

Join Date: Apr 2008
Posts: 8
Reputation: OriginalCopy is an unknown quantity at this point 
Solved Threads: 1
OriginalCopy OriginalCopy is offline Offline
Newbie Poster

simple calculator using a scanner (re2c) and a parser generator (lemon)

 
0
  #1
Oct 9th, 2008
Hi. The following calculator will return wrong values for operations which are more complicated than <INTEGER><OPERATION><INTEGER>. I suppose I'm making a mistake in parser.y, but I can't figure out what.

I know there are mistakes, memory leaks and other technical issues I'm doing wrong, but please concentrate on my biggest issue.

The code

  1. //--------------------------------------------------------- ./handcrafted_parser.c
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include "scanner.h"
  6.  
  7. int main(int argc, char **argv) {
  8. int r;
  9. scanner_state *state;
  10. scanner_token *token;
  11. if(argc>1) {
  12. state = malloc(sizeof(scanner_state));
  13. token = malloc(sizeof(scanner_token));
  14. if(NULL == state || NULL == token) {
  15. return EXIT_FAILURE;
  16. }
  17. state->start = argv[1];
  18. //it's here, but not used:
  19. state->end = state->start;
  20. while(0 <= (r = scan(state, token))) {
  21. switch(token->opcode) {
  22. case T_INTEGER:
  23. printf("\tscanner: %d\n",token->data.n);
  24. break;
  25. case T_OP_ADD:
  26. case T_OP_SUB:
  27. case T_OP_MUL:
  28. case T_OP_DIV:
  29. case T_OP_ROUND_BRACKET_OPEN:
  30. case T_OP_ROUND_BRACKET_CLOSE:
  31. printf("\tscanner: %c\n",token->opcode);
  32. break;
  33. default:
  34. printf("\tscanner: unknown opcode\n");
  35. break;
  36. }
  37. //it's here, but not used:
  38. state->end = state->start;
  39. }
  40. printf("\nend of scanning with code: %d\n",r);
  41. free(state);
  42. free(token);
  43. return SCANNER_RETCODE_EOF==r ? EXIT_SUCCESS:EXIT_FAILURE;
  44. }
  45. else {
  46. return EXIT_FAILURE;
  47. }
  48. return EXIT_SUCCESS;
  49. }
  50.  
  51.  
  52.  
  53.  
  54. //--------------------------------------------------------- ./lemon_parser.h
  55. #ifndef _LEMON_PARSER_H
  56. # define _LEMON_PARSER_H
  57. # include "scanner.h"
  58.  
  59. scanner_token parse_math_expr(char* s);
  60.  
  61. #endif
  62.  
  63.  
  64.  
  65. //--------------------------------------------------------- ./lemon_parser.c
  66. /*
  67.  * this is the "main part" of the parser
  68.  * gets concatenated to parser.c, which is generated by lemon parser.y
  69.  */
  70.  
  71. /*
  72.  * include types, we do it here for the sake of obviousness,
  73.  * these headers are actually included by parser.c, which is
  74.  * generated by parser.y
  75.  */
  76. #include "scanner.h"
  77. #include "parser.h"
  78. #include "lemon_parser.h"
  79.  
  80. scanner_token parse_math_expr(char* s) {
  81. scanner_token *token;
  82. scanner_state *state;
  83. int stat;
  84. //TODO: fix memory leaks
  85. void* pParser = ParseAlloc(malloc);
  86. //do similar things to handcrafted_parser.c
  87. state = malloc(sizeof(scanner_state));
  88. token = malloc(sizeof(scanner_token));
  89. if(NULL == state || NULL == token) {
  90. return *token;
  91. }
  92. state->start = s;
  93. while(0 <= (stat = scan(state,token))) {
  94. switch(token->opcode) {
  95. case TOKEN_INTEGER:
  96. printf("\tscanner says: %d\n",token->data.n);
  97. Parse(pParser,OP_INTEGER,token);
  98. break;
  99. case TOKEN_ADD:
  100. printf("\tscanner: %c\n",token->opcode);
  101. Parse(pParser,OP_ADD,token);
  102. break;
  103. case TOKEN_SUB:
  104. printf("\tscanner: %c\n",token->opcode);
  105. Parse(pParser,OP_SUB,token);
  106. break;
  107. case TOKEN_MUL:
  108. printf("\tscanner: %c\n",token->opcode);
  109. Parse(pParser,OP_MUL,token);
  110. break;
  111. case TOKEN_DIV:
  112. printf("\tscanner: %c\n",token->opcode);
  113. Parse(pParser,OP_DIV,token);
  114. break;
  115. /*
  116. case OP_ROUND_BRACKET_OPEN:
  117. printf("\tscanner: %c\n",token->opcode);
  118. break;
  119. case OP_ROUND_BRACKET_CLOSE:
  120. printf("\tscanner: %c\n",token->opcode);
  121. break;
  122. */
  123. default:
  124. printf("\tscanner: unknown opcode: %c\n",token->opcode);
  125. break;
  126. }
  127. //it's here, but not used:
  128. state->end = state->start;
  129. }
  130. Parse(pParser,0,0);
  131. return *token;
  132. }
  133.  
  134.  
  135.  
  136.  
  137. //--------------------------------------------------------- ./parser.y
  138. %include {
  139. #include <stdio.h>
  140. #include <stdlib.h>
  141. #include "scanner.h"
  142. #include "parser.h"
  143. #include "lemon_parser.h"
  144. }
  145. %token_type {scanner_token*}
  146. %default_type {scanner_token*}
  147.  
  148. %type expr {scanner_token*}
  149. %type OP_INTEGER {scanner_token*}
  150.  
  151.  
  152.  
  153. %left OP_ADD OP_SUB.
  154. %left OP_MUL OP_DIV.
  155.  
  156.  
  157. %syntax_error {
  158. printf("syntax error\n");
  159. }
  160.  
  161. in ::= expr(A). {
  162. printf("in expr(A):\n");
  163. }
  164.  
  165. expr(A) ::= expr(B) OP_ADD expr(C). {
  166. A->data.n = B->data.n + C->data.n;
  167. }
  168.  
  169. expr(A) ::= expr(B) OP_SUB expr(C). {
  170. A->data.n = B->data.n - C->data.n;
  171. }
  172.  
  173. expr(A) ::= expr(B) OP_MUL expr(C). {
  174. A->data.n = B->data.n * C->data.n;
  175. }
  176.  
  177. expr(A) ::= expr(B) OP_DIV expr(C). {
  178. /* TODO: fix division by 0 */
  179. A->data.n = B->data.n / C->data.n;
  180. }
  181. expr(A) ::= OP_INTEGER(B). { A->data.n = B->data.n; }
  182.  
  183.  
  184.  
  185.  
  186.  
  187. //--------------------------------------------------------- ./Makefile
  188. CC = gcc
  189. RE2C = re2c
  190. CFLAGS = -Wall -ggdb -c
  191. RE2C_FLAGS =
  192.  
  193. all: calc handcrafted_parser parser
  194.  
  195. calc: scanner.o main.o parser.o
  196. $(CC) -Wall -o $@ $?
  197.  
  198. scanner.o: scanner.c
  199. $(CC) $(CFLAGS) $?
  200. scanner.c: scanner.re
  201. $(RE2C) $(RE2C_FLAGS) -o $@ $?
  202. $(RE2C) -D -o scanner.graphviz $?
  203. main.o: main.c
  204. $(CC) $(CFLAGS) $?
  205. handcrafted_parser: handcrafted_parser.o
  206. $(CC) -Wall -o $@ $?
  207. handcrafted_parser.o: handcrafted_parser.c
  208. $(CC) $(CFLAGS) $?
  209. parser.o: parser.c
  210. cat lemon_parser.c >> parser.c
  211. $(CC) $(CFLAGS) $?
  212.  
  213. parser.c: lemon
  214. ./lemon parser.y
  215.  
  216. lemon: lemon.o
  217. $(CC) -Wall -o $@ $?
  218. lemon.o:
  219. $(CC) -o $@ $(CFLAGS) lemon.c $<
  220.  
  221. clean:
  222. rm -f *.o calc handcrafted_parser parser.{c,h,out}
  223. distclean: clean
  224. rm -f scanner.c scanner.graphviz lemon
  225.  
  226.  
  227.  
  228. //--------------------------------------------------------- ./main.c
  229. #include <stdio.h>
  230. #include <stdlib.h>
  231. #include <string.h>
  232. //defines the parse() function
  233. #include "lemon_parser.h"
  234.  
  235. int main(int argc, char **argv) {
  236. scanner_token result;
  237. result = parse_math_expr(argv[1]);
  238. printf("calc(%s) = %d\n",argv[1],result.data.n);
  239. return EXIT_SUCCESS;
  240. }
  241.  
  242.  
  243.  
  244.  
  245. //--------------------------------------------------------- ./scanner.h
  246. #ifndef _SCANNER_H
  247. # define _SCANNER_H
  248.  
  249. /*
  250.  * opcodes:
  251.  */
  252. #define SCANNER_RETCODE_EOF -1
  253. #define SCANNER_RETCODE_ERR -2
  254. #define SCANNER_RETCODE_IMPOSSIBLE -3
  255.  
  256. #define TOKEN_INTEGER 257
  257. #define TOKEN_ADD '+'
  258. #define TOKEN_SUB '-'
  259. #define TOKEN_MUL '*'
  260. #define TOKEN_DIV '/'
  261. #define TOKEN_ROUND_BRACKET_OPEN '('
  262. #define TOKEN_ROUND_BRACKET_CLOSE ')'
  263.  
  264. typedef struct _scanner_state {
  265. char* start;
  266. char* end;
  267. } scanner_state;
  268.  
  269. typedef struct _scanner_token {
  270. int opcode;
  271. union {
  272. int n;
  273. char* str;
  274. } data;
  275. } scanner_token;
  276.  
  277. int scan(scanner_state *state, scanner_token *token);
  278. //TODO: some functions to manipulate scanner states
  279. #endif
  280.  
  281.  
  282.  
  283.  
  284. //--------------------------------------------------------- ./scanner.re
  285. #define _GNU_SOURCE
  286. #include <stdio.h>
  287. #include <stdlib.h>
  288. #include <string.h>
  289. #define _IN_SCANNER
  290. #include "scanner.h"
  291.  
  292. #if 0
  293. #define DEBUG(stmt) stmt
  294. #else
  295. #define DEBUG(stmt)
  296. #endif
  297.  
  298. int scan(scanner_state *s, scanner_token *token) {
  299. // char *cursor = s->start;
  300. int r=SCANNER_RETCODE_IMPOSSIBLE;
  301. char *q=s->start;//keep initial start
  302. #define YYCTYPE char
  303. #define YYCURSOR (s->start)
  304. #define YYLIMIT (s->end)
  305.  
  306. while(SCANNER_RETCODE_IMPOSSIBLE == r) {
  307. /*!re2c
  308.   re2c:indent:top = 2;
  309. re2c:yyfill:enable = 0;
  310.  
  311. INTEGER = [0-9]+;
  312.  
  313.  
  314. INTEGER {
  315. char *num;
  316. int n;
  317. num = strndup(q,YYCURSOR - q);
  318. n = atoi(num);
  319. DEBUG(printf("scanner num: '%s', YYCURSOR: '%s' YYLIMIT: '%s' q: '%s'\n",num,YYCURSOR,YYLIMIT,q));
  320. free(num);
  321. q = YYCURSOR;
  322. // DEBUG(printf("integer, cursor: %s, number len: %ld, number: %d\n",YYCURSOR,YYCURSOR-s->start,n));
  323. token->data.n = n;
  324. token->opcode = TOKEN_INTEGER;
  325. return 0;
  326. }
  327. "+" {
  328. token->opcode = TOKEN_ADD;
  329. return 0;
  330. }
  331. "-" {
  332. token->opcode = TOKEN_SUB;
  333. return 0;
  334. }
  335. "*" {
  336. token->opcode = TOKEN_MUL;
  337. return 0;
  338. }
  339. "/" {
  340. token->opcode = TOKEN_DIV;
  341. return 0;
  342. }
  343. "(" {
  344. token->opcode = TOKEN_ROUND_BRACKET_OPEN;
  345. return 0;
  346. }
  347. ")" {
  348. token->opcode = TOKEN_ROUND_BRACKET_CLOSE;
  349. return 0;
  350. }
  351.  
  352. "\000" { r = SCANNER_RETCODE_EOF; break; }
  353. [^] { r = SCANNER_RETCODE_ERR; break; }
  354. */
  355. }
  356. return r;
  357. }
Last edited by OriginalCopy; Oct 9th, 2008 at 3:19 pm.
Reply With Quote Quick reply to this message  
Join Date: Jul 2008
Posts: 113
Reputation: ahamed101 is an unknown quantity at this point 
Solved Threads: 14
ahamed101's Avatar
ahamed101 ahamed101 is offline Offline
Junior Poster

Re: simple calculator using a scanner (re2c) and a parser generator (lemon)

 
0
  #2
Oct 11th, 2008
Hi,
this code is tooooo big to analyse... tell us whats the issue you are facing(be specific) so that we can help you...
regards,
Ahamed.
Reply With Quote Quick reply to this message  
Join Date: Apr 2008
Posts: 8
Reputation: OriginalCopy is an unknown quantity at this point 
Solved Threads: 1
OriginalCopy OriginalCopy is offline Offline
Newbie Poster

Re: simple calculator using a scanner (re2c) and a parser generator (lemon)

 
0
  #3
Oct 11th, 2008
I'm almost done with it, the previous errors are fixed now. The only issue I still have is how to get the last token from the last reduction
("in" in parser.y, but in the current code it looks totally different). The problem is it returns the very last number, ie in "1+2+3" Parse(pParser,0,token) returns the token that contains the value 3.

How to get the result in a thread-safe/reentrand way, just as "lemon" recommends me to do it?
Last edited by OriginalCopy; Oct 11th, 2008 at 6:50 pm.
Reply With Quote Quick reply to this message  
Join Date: Apr 2008
Posts: 8
Reputation: OriginalCopy is an unknown quantity at this point 
Solved Threads: 1
OriginalCopy OriginalCopy is offline Offline
Newbie Poster

Solution

 
0
  #4
Oct 15th, 2008
Done. The working result can be found on "How to Create a Math Calculator in C, the right Way"
Last edited by OriginalCopy; Oct 15th, 2008 at 4:41 am.
Reply With Quote Quick reply to this message  
Join Date: Jul 2008
Posts: 113
Reputation: ahamed101 is an unknown quantity at this point 
Solved Threads: 14
ahamed101's Avatar
ahamed101 ahamed101 is offline Offline
Junior Poster

Re: simple calculator using a scanner (re2c) and a parser generator (lemon)

 
0
  #5
Oct 15th, 2008
Good Job!!!... Please let us know if it was a technical error or logical... if technical, give us a brief note about it...
regards,
Ahamed.
Reply With Quote Quick reply to this message  
Reply

This thread is more than three months old.
Perhaps start a new thread instead?
Message:


Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC