| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- #
- # rosettacode.py
- #
- # parser for language used by rosettacode.org (http://rosettacode.org/wiki/Compiler/syntax_analyzer)
- #
- # Copyright Paul McGuire, 2019
- #
- BNF = """
- stmt_list = {stmt} ;
-
- stmt = ';'
- | Identifier '=' expr ';'
- | 'while' paren_expr stmt
- | 'if' paren_expr stmt ['else' stmt]
- | 'print' '(' prt_list ')' ';'
- | 'putc' paren_expr ';'
- | '{' stmt_list '}'
- ;
-
- paren_expr = '(' expr ')' ;
-
- prt_list = string | expr {',' String | expr} ;
-
- expr = and_expr {'||' and_expr} ;
- and_expr = equality_expr {'&&' equality_expr} ;
- equality_expr = relational_expr [('==' | '!=') relational_expr] ;
- relational_expr = addition_expr [('<' | '<=' | '>' | '>=') addition_expr] ;
- addition_expr = multiplication_expr {('+' | '-') multiplication_expr} ;
- multiplication_expr = primary {('*' | '/' | '%') primary } ;
- primary = Identifier
- | Integer
- | '(' expr ')'
- | ('+' | '-' | '!') primary
- ;
- """
- import pyparsing as pp
- pp.ParserElement.enablePackrat()
- LBRACE, RBRACE, LPAR, RPAR, SEMI = map(pp.Suppress, "{}();")
- EQ = pp.Literal('=')
- keywords = (WHILE, IF, PRINT, PUTC, ELSE) = map(pp.Keyword, "while if print putc else".split())
- identifier = ~(pp.MatchFirst(keywords)) + pp.pyparsing_common.identifier
- integer = pp.pyparsing_common.integer
- string = pp.QuotedString('"', convertWhitespaceEscapes=False).setName("quoted string")
- char = pp.Regex(r"'\\?.'")
- expr = pp.infixNotation(identifier | integer | char,
- [
- (pp.oneOf("+ - !"), 1, pp.opAssoc.RIGHT,),
- (pp.oneOf("* / %"), 2, pp.opAssoc.LEFT, ),
- (pp.oneOf("+ -"), 2, pp.opAssoc.LEFT,),
- (pp.oneOf("< <= > >="), 2, pp.opAssoc.LEFT,),
- (pp.oneOf("== !="), 2, pp.opAssoc.LEFT,),
- (pp.oneOf("&&"), 2, pp.opAssoc.LEFT,),
- (pp.oneOf("||"), 2, pp.opAssoc.LEFT,),
- ])
- prt_list = pp.Group(pp.delimitedList(string | expr))
- paren_expr = pp.Group(LPAR + expr + RPAR)
- stmt = pp.Forward()
- assignment_stmt = pp.Group(identifier + EQ + expr + SEMI)
- while_stmt = pp.Group(WHILE - paren_expr + stmt)
- if_stmt = pp.Group(IF - paren_expr + stmt + pp.Optional(ELSE + stmt))
- print_stmt = pp.Group(PRINT - pp.Group(LPAR + prt_list + RPAR) + SEMI)
- putc_stmt = pp.Group(PUTC - paren_expr + SEMI)
- stmt_list = pp.Group(LBRACE + pp.ZeroOrMore(stmt) + RBRACE)
- stmt <<= (pp.Group(SEMI)
- | assignment_stmt
- | while_stmt
- | if_stmt
- | print_stmt
- | putc_stmt
- | stmt_list
- ).setName("statement")
- code = pp.ZeroOrMore(stmt)
- code.ignore(pp.cppStyleComment)
- tests = [
- r'''
- count = 1;
- while (count < 10) {
- print("count is: ", count, "\n");
- count = count + 1;
- }
- ''',
- r'''
- /*
- Simple prime number generator
- */
- count = 1;
- n = 1;
- limit = 100;
- while (n < limit) {
- k=3;
- p=1;
- n=n+2;
- while ((k*k<=n) && (p)) {
- p=n/k*k!=n;
- k=k+2;
- }
- if (p) {
- print(n, " is prime\n");
- count = count + 1;
- }
- }
- print("Total primes found: ", count, "\n");
- ''',
- r'''
- /*
- Hello world
- */
- print("Hello, World!\n");
- ''',
- r'''
- /*
- Show Ident and Integers
- */
- phoenix_number = 142857;
- print(phoenix_number, "\n");
- ''',
- r'''
- /*** test printing, embedded \n and comments with lots of '*' ***/
- print(42);
- print("\nHello World\nGood Bye\nok\n");
- print("Print a slash n - \\n.\n");
- ''',
- r'''
- /* 100 Doors */
- i = 1;
- while (i * i <= 100) {
- print("door ", i * i, " is open\n");
- i = i + 1;
- }
- ''',
- r'''
- a = (-1 * ((-1 * (5 * 15)) / 10));
- print(a, "\n");
- b = -a;
- print(b, "\n");
- print(-b, "\n");
- print(-(1), "\n");
- ''',
- r'''
- print(---------------------------------+++5, "\n");
- print(((((((((3 + 2) * ((((((2))))))))))))), "\n");
-
- if (1) { if (1) { if (1) { if (1) { if (1) { print(15, "\n"); } } } } }
- ''',
- r'''
- /* Compute the gcd of 1071, 1029: 21 */
-
- a = 1071;
- b = 1029;
-
- while (b != 0) {
- new_a = b;
- b = a % b;
- a = new_a;
- }
- print(a);
- ''',
- r'''
- /* 12 factorial is 479001600 */
-
- n = 12;
- result = 1;
- i = 1;
- while (i <= n) {
- result = result * i;
- i = i + 1;
- }
- print(result);
- ''',
- r'''
- /* fibonacci of 44 is 701408733 */
-
- n = 44;
- i = 1;
- a = 0;
- b = 1;
- while (i < n) {
- w = a + b;
- a = b;
- b = w;
- i = i + 1;
- }
- print(w, "\n");
- ''',
- r'''
- /* FizzBuzz */
- i = 1;
- while (i <= 100) {
- if (!(i % 15))
- print("FizzBuzz");
- else if (!(i % 3))
- print("Fizz");
- else if (!(i % 5))
- print("Buzz");
- else
- print(i);
-
- print("\n");
- i = i + 1;
- }
- ''',
- r'''
- /* 99 bottles */
- bottles = 99;
- while (bottles > 0) {
- print(bottles, " bottles of beer on the wall\n");
- print(bottles, " bottles of beer\n");
- print("Take one down, pass it around\n");
- bottles = bottles - 1;
- print(bottles, " bottles of beer on the wall\n\n");
- }
- ''',
- r'''
- {
- /*
- This is an integer ascii Mandelbrot generator
- */
- left_edge = -420;
- right_edge = 300;
- top_edge = 300;
- bottom_edge = -300;
- x_step = 7;
- y_step = 15;
-
- max_iter = 200;
-
- y0 = top_edge;
- while (y0 > bottom_edge) {
- x0 = left_edge;
- while (x0 < right_edge) {
- y = 0;
- x = 0;
- the_char = ' ';
- i = 0;
- while (i < max_iter) {
- x_x = (x * x) / 200;
- y_y = (y * y) / 200;
- if (x_x + y_y > 800 ) {
- the_char = '0' + i;
- if (i > 9) {
- the_char = '@';
- }
- i = max_iter;
- }
- y = x * y / 100 + y0;
- x = x_x - y_y + x0;
- i = i + 1;
- }
- putc(the_char);
- x0 = x0 + x_step;
- }
- putc('\n');
- y0 = y0 - y_step;
- }
- }
- ''',
- ]
- import sys
- sys.setrecursionlimit(2000)
- for test in tests:
- try:
- results = code.parseString(test)
- except pp.ParseException as pe:
- pp.ParseException.explain(pe)
- else:
- results.pprint()
- print()
|