rosettacode.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. #
  2. # rosettacode.py
  3. #
  4. # parser for language used by rosettacode.org (http://rosettacode.org/wiki/Compiler/syntax_analyzer)
  5. #
  6. # Copyright Paul McGuire, 2019
  7. #
  8. BNF = """
  9. stmt_list = {stmt} ;
  10. stmt = ';'
  11. | Identifier '=' expr ';'
  12. | 'while' paren_expr stmt
  13. | 'if' paren_expr stmt ['else' stmt]
  14. | 'print' '(' prt_list ')' ';'
  15. | 'putc' paren_expr ';'
  16. | '{' stmt_list '}'
  17. ;
  18. paren_expr = '(' expr ')' ;
  19. prt_list = string | expr {',' String | expr} ;
  20. expr = and_expr {'||' and_expr} ;
  21. and_expr = equality_expr {'&&' equality_expr} ;
  22. equality_expr = relational_expr [('==' | '!=') relational_expr] ;
  23. relational_expr = addition_expr [('<' | '<=' | '>' | '>=') addition_expr] ;
  24. addition_expr = multiplication_expr {('+' | '-') multiplication_expr} ;
  25. multiplication_expr = primary {('*' | '/' | '%') primary } ;
  26. primary = Identifier
  27. | Integer
  28. | '(' expr ')'
  29. | ('+' | '-' | '!') primary
  30. ;
  31. """
  32. import pyparsing as pp
  33. pp.ParserElement.enablePackrat()
  34. LBRACE, RBRACE, LPAR, RPAR, SEMI = map(pp.Suppress, "{}();")
  35. EQ = pp.Literal('=')
  36. keywords = (WHILE, IF, PRINT, PUTC, ELSE) = map(pp.Keyword, "while if print putc else".split())
  37. identifier = ~(pp.MatchFirst(keywords)) + pp.pyparsing_common.identifier
  38. integer = pp.pyparsing_common.integer
  39. string = pp.QuotedString('"', convertWhitespaceEscapes=False).setName("quoted string")
  40. char = pp.Regex(r"'\\?.'")
  41. expr = pp.infixNotation(identifier | integer | char,
  42. [
  43. (pp.oneOf("+ - !"), 1, pp.opAssoc.RIGHT,),
  44. (pp.oneOf("* / %"), 2, pp.opAssoc.LEFT, ),
  45. (pp.oneOf("+ -"), 2, pp.opAssoc.LEFT,),
  46. (pp.oneOf("< <= > >="), 2, pp.opAssoc.LEFT,),
  47. (pp.oneOf("== !="), 2, pp.opAssoc.LEFT,),
  48. (pp.oneOf("&&"), 2, pp.opAssoc.LEFT,),
  49. (pp.oneOf("||"), 2, pp.opAssoc.LEFT,),
  50. ])
  51. prt_list = pp.Group(pp.delimitedList(string | expr))
  52. paren_expr = pp.Group(LPAR + expr + RPAR)
  53. stmt = pp.Forward()
  54. assignment_stmt = pp.Group(identifier + EQ + expr + SEMI)
  55. while_stmt = pp.Group(WHILE - paren_expr + stmt)
  56. if_stmt = pp.Group(IF - paren_expr + stmt + pp.Optional(ELSE + stmt))
  57. print_stmt = pp.Group(PRINT - pp.Group(LPAR + prt_list + RPAR) + SEMI)
  58. putc_stmt = pp.Group(PUTC - paren_expr + SEMI)
  59. stmt_list = pp.Group(LBRACE + pp.ZeroOrMore(stmt) + RBRACE)
  60. stmt <<= (pp.Group(SEMI)
  61. | assignment_stmt
  62. | while_stmt
  63. | if_stmt
  64. | print_stmt
  65. | putc_stmt
  66. | stmt_list
  67. ).setName("statement")
  68. code = pp.ZeroOrMore(stmt)
  69. code.ignore(pp.cppStyleComment)
  70. tests = [
  71. r'''
  72. count = 1;
  73. while (count < 10) {
  74. print("count is: ", count, "\n");
  75. count = count + 1;
  76. }
  77. ''',
  78. r'''
  79. /*
  80. Simple prime number generator
  81. */
  82. count = 1;
  83. n = 1;
  84. limit = 100;
  85. while (n < limit) {
  86. k=3;
  87. p=1;
  88. n=n+2;
  89. while ((k*k<=n) && (p)) {
  90. p=n/k*k!=n;
  91. k=k+2;
  92. }
  93. if (p) {
  94. print(n, " is prime\n");
  95. count = count + 1;
  96. }
  97. }
  98. print("Total primes found: ", count, "\n");
  99. ''',
  100. r'''
  101. /*
  102. Hello world
  103. */
  104. print("Hello, World!\n");
  105. ''',
  106. r'''
  107. /*
  108. Show Ident and Integers
  109. */
  110. phoenix_number = 142857;
  111. print(phoenix_number, "\n");
  112. ''',
  113. r'''
  114. /*** test printing, embedded \n and comments with lots of '*' ***/
  115. print(42);
  116. print("\nHello World\nGood Bye\nok\n");
  117. print("Print a slash n - \\n.\n");
  118. ''',
  119. r'''
  120. /* 100 Doors */
  121. i = 1;
  122. while (i * i <= 100) {
  123. print("door ", i * i, " is open\n");
  124. i = i + 1;
  125. }
  126. ''',
  127. r'''
  128. a = (-1 * ((-1 * (5 * 15)) / 10));
  129. print(a, "\n");
  130. b = -a;
  131. print(b, "\n");
  132. print(-b, "\n");
  133. print(-(1), "\n");
  134. ''',
  135. r'''
  136. print(---------------------------------+++5, "\n");
  137. print(((((((((3 + 2) * ((((((2))))))))))))), "\n");
  138. if (1) { if (1) { if (1) { if (1) { if (1) { print(15, "\n"); } } } } }
  139. ''',
  140. r'''
  141. /* Compute the gcd of 1071, 1029: 21 */
  142. a = 1071;
  143. b = 1029;
  144. while (b != 0) {
  145. new_a = b;
  146. b = a % b;
  147. a = new_a;
  148. }
  149. print(a);
  150. ''',
  151. r'''
  152. /* 12 factorial is 479001600 */
  153. n = 12;
  154. result = 1;
  155. i = 1;
  156. while (i <= n) {
  157. result = result * i;
  158. i = i + 1;
  159. }
  160. print(result);
  161. ''',
  162. r'''
  163. /* fibonacci of 44 is 701408733 */
  164. n = 44;
  165. i = 1;
  166. a = 0;
  167. b = 1;
  168. while (i < n) {
  169. w = a + b;
  170. a = b;
  171. b = w;
  172. i = i + 1;
  173. }
  174. print(w, "\n");
  175. ''',
  176. r'''
  177. /* FizzBuzz */
  178. i = 1;
  179. while (i <= 100) {
  180. if (!(i % 15))
  181. print("FizzBuzz");
  182. else if (!(i % 3))
  183. print("Fizz");
  184. else if (!(i % 5))
  185. print("Buzz");
  186. else
  187. print(i);
  188. print("\n");
  189. i = i + 1;
  190. }
  191. ''',
  192. r'''
  193. /* 99 bottles */
  194. bottles = 99;
  195. while (bottles > 0) {
  196. print(bottles, " bottles of beer on the wall\n");
  197. print(bottles, " bottles of beer\n");
  198. print("Take one down, pass it around\n");
  199. bottles = bottles - 1;
  200. print(bottles, " bottles of beer on the wall\n\n");
  201. }
  202. ''',
  203. r'''
  204. {
  205. /*
  206. This is an integer ascii Mandelbrot generator
  207. */
  208. left_edge = -420;
  209. right_edge = 300;
  210. top_edge = 300;
  211. bottom_edge = -300;
  212. x_step = 7;
  213. y_step = 15;
  214. max_iter = 200;
  215. y0 = top_edge;
  216. while (y0 > bottom_edge) {
  217. x0 = left_edge;
  218. while (x0 < right_edge) {
  219. y = 0;
  220. x = 0;
  221. the_char = ' ';
  222. i = 0;
  223. while (i < max_iter) {
  224. x_x = (x * x) / 200;
  225. y_y = (y * y) / 200;
  226. if (x_x + y_y > 800 ) {
  227. the_char = '0' + i;
  228. if (i > 9) {
  229. the_char = '@';
  230. }
  231. i = max_iter;
  232. }
  233. y = x * y / 100 + y0;
  234. x = x_x - y_y + x0;
  235. i = i + 1;
  236. }
  237. putc(the_char);
  238. x0 = x0 + x_step;
  239. }
  240. putc('\n');
  241. y0 = y0 - y_step;
  242. }
  243. }
  244. ''',
  245. ]
  246. import sys
  247. sys.setrecursionlimit(2000)
  248. for test in tests:
  249. try:
  250. results = code.parseString(test)
  251. except pp.ParseException as pe:
  252. pp.ParseException.explain(pe)
  253. else:
  254. results.pprint()
  255. print()