| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- # oc.py
- #
- # A subset-C parser, (BNF taken from 1996 International Obfuscated C Code Contest)
- #
- # Copyright, 2010, Paul McGuire
- #
- """
- https://www.ioccc.org/1996/august.hint
- The following is a description of the OC grammar:
- OC grammar
- ==========
- Terminals are in quotes, () is used for bracketing.
- program: decl*
- decl: vardecl
- fundecl
- vardecl: type NAME ;
- type NAME "[" INT "]" ;
- fundecl: type NAME "(" args ")" "{" body "}"
- args: /*empty*/
- ( arg "," )* arg
- arg: type NAME
- body: vardecl* stmt*
- stmt: ifstmt
- whilestmt
- dowhilestmt
- "return" expr ";"
- expr ";"
- "{" stmt* "}"
- ";"
- ifstmt: "if" "(" expr ")" stmt
- "if" "(" expr ")" stmt "else" stmt
- whilestmt: "while" "(" expr ")" stmt
- dowhilestmt: "do" stmt "while" "(" expr ")" ";"
- expr: expr binop expr
- unop expr
- expr "[" expr "]"
- "(" expr ")"
- expr "(" exprs ")"
- NAME
- INT
- CHAR
- STRING
- exprs: /*empty*/
- (expr ",")* expr
- binop: "+" | "-" | "*" | "/" | "%" |
- "=" |
- "<" | "==" | "!="
- unop: "!" | "-" | "*"
- type: "int" stars
- "char" stars
- stars: "*"*
- """
- from pyparsing import *
- ParserElement.enablePackrat()
- LPAR,RPAR,LBRACK,RBRACK,LBRACE,RBRACE,SEMI,COMMA = map(Suppress, "()[]{};,")
- INT, CHAR, WHILE, DO, IF, ELSE, RETURN = map(Keyword,
- "int char while do if else return".split())
- NAME = Word(alphas+"_", alphanums+"_")
- integer = Regex(r"[+-]?\d+")
- char = Regex(r"'.'")
- string_ = dblQuotedString
- TYPE = Group((INT | CHAR) + ZeroOrMore("*"))
- expr = Forward()
- func_call = Group(NAME + LPAR + Group(Optional(delimitedList(expr))) + RPAR)
- operand = func_call | NAME | integer | char | string_
- expr <<= (infixNotation(operand,
- [
- (oneOf('! - *'), 1, opAssoc.RIGHT),
- (oneOf('++ --'), 1, opAssoc.RIGHT),
- (oneOf('++ --'), 1, opAssoc.LEFT),
- (oneOf('* / %'), 2, opAssoc.LEFT),
- (oneOf('+ -'), 2, opAssoc.LEFT),
- (oneOf('< == > <= >= !='), 2, opAssoc.LEFT),
- (Regex(r'(?<!=)=(?!=)'), 2, opAssoc.LEFT),
- ]) +
- Optional( LBRACK + expr + RBRACK |
- LPAR + Group(Optional(delimitedList(expr))) + RPAR )
- )
- stmt = Forward()
- ifstmt = IF - LPAR + expr + RPAR + stmt + Optional(ELSE + stmt)
- whilestmt = WHILE - LPAR + expr + RPAR + stmt
- dowhilestmt = DO - stmt + WHILE + LPAR + expr + RPAR + SEMI
- returnstmt = RETURN - expr + SEMI
- stmt << Group( ifstmt |
- whilestmt |
- dowhilestmt |
- returnstmt |
- expr + SEMI |
- LBRACE + ZeroOrMore(stmt) + RBRACE |
- SEMI)
- vardecl = Group(TYPE + NAME + Optional(LBRACK + integer + RBRACK)) + SEMI
- arg = Group(TYPE + NAME)
- body = ZeroOrMore(vardecl) + ZeroOrMore(stmt)
- fundecl = Group(TYPE + NAME + LPAR + Optional(Group(delimitedList(arg))) + RPAR +
- LBRACE + Group(body) + RBRACE)
- decl = fundecl | vardecl
- program = ZeroOrMore(decl)
- program.ignore(cStyleComment)
- # set parser element names
- for vname in ("ifstmt whilestmt dowhilestmt returnstmt TYPE "
- "NAME fundecl vardecl program arg body stmt".split()):
- v = vars()[vname]
- v.setName(vname)
- #~ for vname in "fundecl stmt".split():
- #~ v = vars()[vname]
- #~ v.setDebug()
- test = r"""
- /* A factorial program */
- int
- putstr(char *s)
- {
- while(*s)
- putchar(*s++);
- }
- int
- fac(int n)
- {
- if (n == 0)
- return 1;
- else
- return n*fac(n-1);
- }
- int
- putn(int n)
- {
- if (9 < n)
- putn(n / 10);
- putchar((n%10) + '0');
- }
- int
- facpr(int n)
- {
- putstr("factorial ");
- putn(n);
- putstr(" = ");
- putn(fac(n));
- putstr("\n");
- }
- int
- main()
- {
- int i;
- i = 0;
- if(a() == 1){}
- while(i < 10)
- facpr(i++);
- return 0;
- }
- """
- ast = program.parseString(test, parseAll=True)
- ast.pprint()
|