Created
July 26, 2013 19:26
-
-
Save mystor/6091570 to your computer and use it in GitHub Desktop.
Quick port of [this gist](https://gist.github.com/Mystor/6086481) to Python using PLY
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ################ | |
| # ENTERING LEX # | |
| ################ | |
| ### | |
| # Define Tokens | |
| ### | |
| tokens = ( | |
| 'COURSE', | |
| 'RECOMMEND', | |
| 'PREREQUISITE', | |
| 'COREQUISITE', | |
| 'EQUIVALENCY', | |
| 'EXCLUSION', | |
| 'OR', | |
| 'LPAREN', | |
| 'RPAREN', | |
| ) | |
| t_RECOMMEND = r'(?i)recommend' | |
| t_PREREQUISITE = r'(?i)prerequisite' | |
| t_COREQUISITE = r'(?i)corequisite' | |
| t_EQUIVALENCY = r'(?i)equivalen' | |
| t_EXCLUSION = r'(?i)exclu' | |
| t_OR = r'(?i)or' | |
| t_LPAREN = r'\(' | |
| t_RPAREN = r'\)' | |
| # t_COURSE = r'[a-zA-Z][a-zA-Z][a-zA-Z][a-zA-Z] [pP]?[0-9][0-9][0-9]' | |
| t_COURSE = r'[a-zA-Z]{4}[ ]?[pP]?[0-9]{1,3}' | |
| def t_error(t): | |
| # Skip any invalid characters | |
| t.lexer.skip(1) | |
| # Build the lexer | |
| import ply.lex as lex | |
| lt = lex.lex() | |
| ################# | |
| # ENTERING YACC # | |
| ################# | |
| ### | |
| # Parsing Rules | |
| ### | |
| precedence = ( | |
| ('right', 'OR'), | |
| ) | |
| ### | |
| # Full document | |
| ### | |
| def p_full(t): | |
| 'full : reqsetlist' | |
| t[0] = t[1] | |
| # Print it out | |
| print(t[0]) | |
| ### | |
| # REQSETLIST DEFINITIONS | |
| ### | |
| def p_reqsetlist_empty(t): | |
| 'reqsetlist : ' | |
| t[0] = [] | |
| def p_reqsetlist_add(t): | |
| 'reqsetlist : reqsetlist reqset' | |
| if len(t[2]['courses']['items']) is 0: | |
| t[0] = t[1] | |
| else: | |
| t[0] = t[1] + [ t[2] ] | |
| ### | |
| # REQSET DEFINITIONS | |
| ### | |
| def p_reqset_recommend(t): | |
| 'reqset : RECOMMEND courselist' | |
| t[0] = { | |
| 'type': 'recommend', | |
| 'courses': t[2] | |
| } | |
| def p_reqset_corequisite(t): | |
| 'reqset : COREQUISITE courselist' | |
| t[0] = { | |
| 'type': 'corequisite', | |
| 'courses': t[2] | |
| } | |
| def p_reqset_prerequisite(t): | |
| 'reqset : PREREQUISITE courselist' | |
| t[0] = { | |
| 'type': 'prerequisite', | |
| 'courses': t[2] | |
| } | |
| def p_reqset_equivalency(t): | |
| 'reqset : EQUIVALENCY courselist' | |
| t[0] = { | |
| 'type': 'equivalency', | |
| 'courses': t[2] | |
| } | |
| def p_reqset_exclusion(t): | |
| 'reqset : EXCLUSION courselist' | |
| t[0] = { | |
| 'type': 'exclusion', | |
| 'courses': t[2] | |
| } | |
| def p_reqset_bare(t): | |
| 'reqset : courselist' | |
| # Default to prerequisites | |
| t[0] = { | |
| 'type': 'prerequisite', | |
| 'courses': t[1] | |
| } | |
| ### | |
| # COURSELIST DEFINITIONS | |
| ### | |
| def p_courselist_single(t): | |
| 'courselist : COURSE' | |
| t[0] = { | |
| 'type': 'and', | |
| 'items': [t[1]] | |
| } | |
| def p_courselist_noop(t): | |
| 'courselist : courselist courselist' | |
| t[0] = courselist_and(t[1], t[2]) | |
| def p_courselist_or(t): | |
| 'courselist : leftor courselist' | |
| t[0] = courselist_or(t[1], t[2]) | |
| def p_courselist_floatingor(t): | |
| 'courselist : leftor' | |
| t[0] = t[1] | |
| def p_courselist_parens(t): | |
| 'courselist : LPAREN courselist RPAREN' | |
| # This simply ensures that the entire courselist inside | |
| # of the parens has already been evaluated | |
| t[0] = t[2] | |
| ### | |
| # OR | |
| ### | |
| def p_leftor(t): | |
| 'leftor : courselist OR' | |
| t[0] = t[1] | |
| def p_error(p): | |
| # Skipping bad tokens | |
| yacc.errok() | |
| # Build the Parser | |
| import ply.yacc as yacc | |
| yacc.yacc() | |
| #################### | |
| # ENTERING HELPERS # | |
| #################### | |
| def courselist_and(a, b): | |
| if a['type'] is 'and' and b['type'] is 'and': | |
| return { | |
| 'type': 'and', | |
| 'items': a['items'] + b['items'] | |
| } | |
| elif a['type'] is 'and' and b['type'] is 'or': | |
| return { | |
| 'type': 'and', | |
| 'items': a['items'] + [ b ] | |
| } | |
| elif a['type'] is 'or' and b['type'] is 'and': | |
| return { | |
| 'type': 'and', | |
| 'items': [ a ] + b['items'] | |
| } | |
| else: | |
| return { | |
| 'type': 'and', | |
| 'items': [a, b] | |
| } | |
| def courselist_or(a, b): | |
| if a['type'] is 'and' and b['type'] is 'and': | |
| # Collapse single element ands | |
| if len(a['items']) is 1: | |
| a = a['items'][0] | |
| if len(b['items']) is 1: | |
| b = b['items'][0] | |
| return { | |
| 'type': 'or', | |
| 'items': [a, b] | |
| } | |
| elif a['type'] is 'and' and b['type'] is 'or': | |
| # Collapse single element ands | |
| if len(a['items']) is 1: | |
| a = a['items'][0] | |
| return { | |
| 'type': 'or', | |
| 'items': [ a ] + b['items'] | |
| } | |
| elif a['type'] is 'or' and b['type'] is 'and': | |
| # Collapse single element ands | |
| if len(b['items']) is 1: | |
| b = b['items'][0] | |
| return { | |
| 'type': 'or', | |
| 'items': a['items'] + [ b ] | |
| } | |
| else: | |
| return { | |
| 'type': 'or', | |
| 'items': a['items'] + b['items'] | |
| } | |
| ################## | |
| # ENTERING TESTS # | |
| ################## | |
| if __name__ == '__main__': | |
| strings = [ | |
| "Must be registered in a BSCE or UENG program. COURSE", | |
| "APSC 131 OR CHEM 120", | |
| "APSC 293 Cor req", | |
| "Recommendation BIOL 201 and BIOL 202. Prerequisite A minimum grade of C- in BIOL 205.", | |
| "Prerequisite BIOL 308. Prior to registering in the course, students must complete the application process, be placed in a module and complete the field work.", | |
| "Prerequisites BIOL 201 and BIOL 202 and (a minimum grade of C- in BIOL 206) and (BIOL 243 or PSYC 202 or STAT 269)." | |
| ] | |
| for string in strings: | |
| print(string) | |
| # lt.input(string) | |
| # while True: | |
| # tok = lt.token() | |
| # if not tok: break | |
| # print tok | |
| yacc.parse(string) | |
| # Horizontal Rule | |
| print('*' * 80) | |
| print('') | |
| print('done') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ply==3.4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment