<CIF2 grammar>= import ply.yacc as yacc from cif_lex_2_0 import tokens from StarFile import StarFile,StarBlock <Helper functions> <CIF grammar common features> <CIF2 additions> <Postamble>
<CIF1.1 grammar>= import ply.yacc as yacc from cif_lex_1_1 import tokens from StarFile import StarFile,StarBlock <Helper functions> <CIF grammar common features> <CIF1 specific productions> <Postamble>
<Postamble>= (<-U <-U) parser = yacc.yacc()
<CIF grammar common features>= (<-U <-U) def p_input(p): ''' input : dblock | input dblock | ''' if len(p) == 1: p[0] = StarFile() elif len(p) == 2: p[0] = p[1] else: p[1].merge_fast(p[2]) p[0] = p[1] def p_dblock(p): ''' dblock : DATA_HEADING data_contents | DATA_HEADING ''' heading = p[1][5:] p[0] = StarFile(characterset='unicode') p[0].NewBlock(heading,StarBlock(overwrite=False)) if len(p) == 3: # Traverse our mini AST for dc in p[2]: if dc[0] == 'SAVE': p[0].merge_fast(dc[1],parent=heading) elif dc[0] == 'KVPAIR': p[0][heading].AddItem(dc[1],dc[2],precheck=False) elif dc[0] == 'LOOP': makeloop(p[0][heading],dc[1:]) else: raise SyntaxError, 'Programming error, what is ' + `dc[0]` def p_data_contents(p): ''' data_contents : dataseq | save_frame | data_contents dataseq | data_contents save_frame ''' if len(p) == 2: p[0] = p[1] else: p[0] = p[1] + p[2] def p_dataseq(p): ''' dataseq : data | dataseq data ''' if len(p) == 2: p[0] = [p[1]] else: p[0] = p[1] + [p[2]] def p_data(p): ''' data : top_loop | datakvpair ''' p[0] = p[1] def p_datakvpair(p): ''' datakvpair : DATA_NAME data_value ''' p[0] = ['KVPAIR',p[1],p[2]] def p_top_loop(p): ''' top_loop : LBLOCK loopfield loopvalues ''' p[0] = ['LOOP',p[2],p[3]] def p_loopfield(p): ''' loopfield : DATA_NAME | loopfield DATA_NAME ''' if len(p) == 2: p[0] = [p[1]] else: p[0] = p[1] + [p[2]] def p_loopvalues(p): ''' loopvalues : data_value | loopvalues data_value ''' if len(p) == 2: p[0] = [p[1]] else: p[0] = p[1] + [p[2]] def p_save_frame(p): ''' save_frame : SAVE_HEADING data_contents SAVE_END | SAVE_HEADING SAVE_END ''' heading = p[1][5:] myframe = StarFile(characterset='unicode') myframe.NewBlock(heading,StarBlock(overwrite=False)) if len(p) == 4: # Traverse our mini AST for dc in p[2]: if dc[0] == 'SAVE': myframe.merge_fast(dc[1],parent=heading) elif dc[0] == 'KVPAIR': myframe[heading].AddItem(dc[1],dc[2],precheck=False) elif dc[0] == 'LOOP': makeloop(myframe[heading],dc[1:]) p[0] = [['SAVE',myframe]]
These productions for CIF1 do not include the bracket expressions or separate delimited expressions.
<CIF1 specific productions>= (<-U) def p_data_value(p): ''' data_value : DATA_VALUE_1 | END_SC_LINE ''' p[0] = p[1]
CIF2 most notably adds lists and tables.
<CIF2 additions>= (<-U) def p_data_value(p): ''' data_value : DATA_VALUE_1 | delimited_data_value | END_SC_LINE | square_bracket_expr | curly_bracket_expr ''' p[0] = p[1] def p_delimited_data_value(p): ''' delimited_data_value : TRIPLE_QUOTE_DATA_VALUE | TRIPLE_APOST_DATA_VALUE | SINGLE_QUOTE_DATA_VALUE ''' p[0] = p[1] def p_square_bracket_expr(p): ''' square_bracket_expr : '[' list_builder ']' ''' p[0] = StarList(p[2]) def p_list_builder(p): ''' list_builder : data_value | list_builder data_value | ''' if len(p) == 2: p[0] = [p[1]] elif len(p) == 3: p[0] = p[1] + [p[2]] else: p[0] = [] def p_curly_bracket_expr(p): ''' curly_bracket_expr : '{' table_builder '}' ''' p[0] = StarDict(pairwise(p[2])) def p_table_builder(p): ''' table_builder : delimited_data_value ':' data_value | table_builder delimited_data_value ':' data_value ''' if len(p) == 4: p[0] = [p[1],p[3]] elif len(p) == 5: p[0] = p[1] + [p[2],p[4]]
<Helper functions>= (<-U <-U) def pairwise(iterable): itnext = iter(p[2]).next while 1: yield itnext(),itnext() def makeloop(target_block,loopdata): loop_seq,itemlists = loopdata if itemlists[-1] == []: itemlists.pop(-1) # print 'Making loop with %s' % `itemlists` step_size = len(loop_seq) for col_no in range(step_size): target_block.AddItem(loop_seq[col_no], itemlists[col_no::step_size],precheck=True) # print 'Makeloop constructed %s' % `loopstructure` # now construct the loop try: target_block.CreateLoop(loop_seq) #will raise ValueError on problem except ValueError: error_string = 'Incorrect number of loop values for loop containing %s' % `loop_seq` print >>sys.stderr, error_string raise ValueError, error_string