def parse(self, ee): self.name = ee.tag for e in e.findall(slpsns.bgf_('*')): if e.tag == 'expression': ne = BGF3.Expression() elif e.tag == 'production': ne = BGF3.Production() else: print('Unknown parameter of type', e.tag) ne = None ne.parse(e) self.params.append(ne)
def projectSymbols(xs,ss): if xs.who() == 'Sequence': e = BGF3.Sequence() for x in xs.data: # TODO: now works only for nonterminals if x.wrapped.who() == 'Nonterminal' and x.wrapped.data in ss: m = BGF3.Marked() m.setExpr(BGF3.Expression(x)) e.add(m) else: e.add(x) return e else: print('projectSymbols not implemented for',xs.who()) print('■') sys.exit(1)
def renameNinExpr(namemap,expr): if expr.who() == 'Sequence': e = BGF3.Sequence() for el in expr.data: e.add(BGF3.Expression(renameNinExpr(namemap,el.wrapped))) return e elif expr.who() == 'Nonterminal': e = BGF3.Nonterminal() if expr.data in namemap: e.setName(namemap[expr.data]) else: e.setName(expr.data) return e else: print('Unfinished implementation of renameNin for',expr.who()) print('■') sys.exit(1)
print('id') elif (e1,e2) in [('*','+'),('*','?'),('*','!'),('+','!'),('?','!')]: ren = XBGF3.Step('narrow') yes = True elif (e2,e1) in [('*','+'),('*','?'),('*','!'),('+','!'),('?','!')]: ren = XBGF3.Step('widen') yes = True else: print('ERROR: not in narrowing relation!') sys.exit(1) if yes: print(ren.name+'('+wrapexp(exp,e1)+','+wrapexp(exp,e2)+')') if e1=='!': ren.addParam(exp) elif e1=='+': p = BGF3.Plus() p.setExpr(exp) ren.addParam(BGF3.Expression(p)) elif e1=='*': p = BGF3.Star() p.setExpr(exp) ren.addParam(BGF3.Expression(p)) elif e1=='?': p = BGF3.Optional() p.setExpr(exp) ren.addParam(BGF3.Expression(p)) else: print('ERROR: unknown in modifier!') sys.exit(1) if e2=='!': ren.addParam(exp)
def checkCandidates(indent,key,nt,candidates,masterprods): good = [] for c in candidates: myprods = bgf.getProdsOfN(c) if myprods: print(indent,'√',c,'is defined as',ppseplist(';',map(lambda x:str(x.expr),myprods))) elif c in ['string','int']: # value => compose a fake rule that "defines" value as value # the condition above is hacky (what if there is a nonterminal called "string" or "int"?) print(indent,'√',c,'is a built-in') p = BGF3.Production() p.setNT(c) v = BGF3.Value() v.data = c p.setExpr(BGF3.Expression(v)) else: print(indent,'√',c,'is undefined') if masterprods: print(indent,' ⇒ not a good candidate because its master counterpart is defined') continue else: print(indent,' ⇒ good candidate because both are undefined') good.append(c) continue #print('###my prods:',ppseplist(';',map(lambda x:str(x.expr),myprods))) #print('###masterprods:',ppseplist(';',map(lambda x:str(x.expr),masterprods))) if masterprods: if len(myprods)==1 and len(masterprods)==1: if sameThing(key,myprods[0].expr,None,masterprods[0].expr): print(indent,' ⇒ good candidate because both definitions are identical') good.append(c) elif moreLiberal(myprods[0],masterprods[0]): print(indent,' ⇒ good candidate because it is defined more liberally') good.append(c) else: print(indent,' ⇒ not a good candidate because two definitions do not match') else: cx1 = cx2 = 0 for p in masterprods: for q in myprods: if sameThing(key,q.expr,None,p.expr): cx1 += 1 elif moreLiberal(q,p): cx2 += 1 if cx1 and cx2: print(indent,' ⇒ good candidate because at least',cx1,'rules are identical to and at least',cx2,' rules are more liberal than the master\'s') good.append(c) elif cx1: print(indent,' ⇒ good candidate because at least',cx1,'rules are identical to the master\'s') good.append(c) elif cx2: print(indent,' ⇒ good candidate because at least',cx2,' rules are more liberal than the master\'s') good.append(c) else: print(indent,' ⇒ not a good candidate because multiple unrelated rules are found') elif not nt and len(myprods) == 1 and myprods[0].expr.wrapped.who() == 'Value': # TODO: check this code print(indent,' ⇒ good candidate because',c,'is defined as a built-in') good.append(c) else: print(indent,' ⇒ not a good candidate because',nt,'is undefined') return good
def match(ident,key,xnt,xs,ynt,ys): global cvdict # Input: sequences xsign = makeSignature(xnt,xs) ysign = makeSignature(ynt,ys) #print(' ~>',xsign) #print(' ~>',ysign) matches = {} alltriplets = [] for k in appnd(fst(xsign),fst(ysign)): triplets = [] if k in fst(xsign): xk = fetch(xsign,k) else: xk = [None] if k in fst(ysign): yk = fetch(ysign,k) else: yk = [None] for x in xk: for y in yk: triplets.append((k,x,y)) alltriplets.append(triplets) alltriplets = cartesian(alltriplets) # some sort of verification/robustness check: # making sure each version touches all nonterminals of both sides xnts = snd(xsign) ynts = snd(ysign) for version in alltriplets: xntsl = xnts[:] yntsl = ynts[:] for triplet in version: if triplet[1] in xntsl: xntsl.remove(triplet[1]) if triplet[2] in yntsl: yntsl.remove(triplet[2]) for x in xntsl: version.append((getSign(xsign,x),x,None)) for y in yntsl: version.append((getSign(ysign,y),None,y)) # if len(alltriplets) == 1: # only one version to assume print(ident,'√ Only one version:') version = alltriplets[0] cvdict = {m[1]:m[2] for m in version} unmatched = list(map(lambda a:a[2],filter(lambda a:a[1]==None,version))) disregard = appnd(setmin(snd(xsign),snd(version)),list(map(lambda a:a[1],filter(lambda a:a[2]==None,version)))) #print(' ~version~>',version) for un in unmatched: #print(' ! Unmatched',un) # TODO: now works with only one candidate (cannot make more version out of one) for dis in disregard: sign_un = list(filter(lambda a:a[1]==un,ysign))[0] sign_dis = list(filter(lambda a:a[1]==dis,xsign))[0] #print('sign_un=',sign_un,'sign_dis=',sign_dis) if moreLiberalSign(sign_dis[0],sign_un[0]): print(ident,'☯ Disregarding more liberal signature,') ver2 = [] for m in version: if m[2]==un: ver2.append((sign_un[0] + ' <: ' + sign_dis[0],dis,un)) elif m[1]==dis: #version.remove(m) pass else: ver2.append(m) version = ver2 disregard = appnd(setmin(snd(xsign),snd(version)),list(map(lambda a:a[1],filter(lambda a:a[2]==None,version)))) for dis in disregard: print(ident,'☯ Disregarding',dis+',') #print('DICTS:',dicts[key]) for match in version: if match[2]: print(ident,' ⇒ in',key+':',match[2],'maps to',match[1],'with signature',match[0]) bind(key,match[2],match[1]) #renameNin(match[1],match[2],key) else: bind(key,None,match[1]) #print('DICTS:',dicts[key]) cvdict = {} else: print(ident,'⇒ Multiple mapping versions:') cx = 0 for version in alltriplets: cvdict = {m[1]:m[2] for m in version} cx +=1 print(ident,'? Version',cx,':',joinsort(', ',[str(t[2])+' is '+str(t[1]) for t in version])) unmatched = list(map(lambda a:a[2],filter(lambda a:a[1]==None,version))) disregard = appnd(setmin(snd(xsign),snd(version)),list(map(lambda a:a[1],filter(lambda a:a[2]==None,version)))) disq = False #print(ident,' ~version~>',version) for match in version: good = checkCandidates(ident+' ',key,match[2],[match[1]],master.getProdsOfN(match[2])) if len(good)!=1: print(ident,' ✗ stop checking') disq = True break if disq: #print('unmatch=',unmatched,'disregarded=',disregard) # TODO: should be any combination cs1 = cs2 = '' for y in unmatched: cs1 += getSign(ysign,y) for x in disregard: cs2 += getSign(xsign,x) # extra normalisation cs1 = joinsort('',list(cs1)) cs2 = joinsort('',list(cs2)) if cs1 == cs2: ver2 = [(cs1,'+'.join(disregard),'+'.join(unmatched))] for m in version: if m[2] not in unmatched and m[1] not in disregard: ver2.append(m) alltriplets.append(ver2) print(ident,' ✗ version disqualified, an adapted variant is proposed') else: print(ident,' ✗ version disqualified') else: print(ident,' √ version approved') #print('VERSION:',version) disregardednow = setmin(disregard,'+'.join(list(map(lambda x:x[1],filter(lambda x:x[1] and x[1].find('+')>-1,version)))).split('+')) for dis in disregardednow: print(ident,'☯ Disregarding',dis+',') #print('DICTS:',dicts[key]) nxs = projectSymbols(xs,disregardednow) step = CBGF3.Step('project-inject') p = BGF3.Production() p.nt = nt p.expr = nxs step.addParam(p) cbgfs[key].addStep(step) for match in version: if match[2]: if match[1].find('+')>-1: print(ident,' ⇒',match[2],'maps to',match[1].replace('+',' and '),'with signature',match[0]) bind(key,match[2],match[1])#.split('+') #renameNin(match[1],match[2],key) else: print(ident,' ⇒',match[2],'maps to',match[1],'with signature',match[0]) bind(key,match[2],match[1]) #renameNin(match[1],match[2],key) else: bind(key,None,match[1]) #print('DICTS:',dicts[key]) cvdict = {}
# -*- coding: utf-8 -*- from functools import reduce import os,sys import xml.etree.ElementTree as ET sys.path.append(os.getcwd().split('projects')[0]+'projects/slps/shared/python') import BGF3 import XBGF3 import CBGF3 import slpsns import metrics3 # globals bgfs = {} cbgfs = {} dicts = {} master = BGF3.Grammar() # current version dictionary cvdict = {} def bind(key,nt1,nt2): global dicts if nt1: if nt1 in dicts[key]: if nt2 in dicts[key][nt1].split('+'): print('~~~Confirmed binding',nt1,'to',nt2,'in',key) else: print('~~~Contradicting binding',nt1,'to',dicts[key][nt1],'or',nt2,'in',key) dicts[key][nt1] += '+'+nt2 #print('■') #sys.exit(1) else:
if len(sys.argv) != 5: print( 'This mutation enforces the naming convention in a given BGF grammar.' ) print('Usage:\n ' + sys.argv[0] + ' <from> <to> <bgf-input> <xbgf-output>') print(' where <from> and <to> can be any of the following:') print(' U = upper case - = dash-separated') print(' l = lower case _ = underscore-separated') print(' m = mixed case . = dot-separated') print(' C = camel case s = space-separated') print(' ! = nonseparated') sys.exit(1) nc1 = sys.argv[1] nc2 = sys.argv[2] bgf = BGF3.Grammar() xbgf = XBGF3.Sequence() bgf.parse(sys.argv[3]) for nt in metrics3.var(bgf): if not check(nc1[0], nt): print(nt, 'does not satisfy convention', sys.argv[1]) else: print(nt, '-->', convert(nc1, nc2, nt)) s = XBGF3.Step('rename') n = XBGF3.Wrapping('nonterminal') n.addChild(XBGF3.Leaf('from', nt)) n.addChild(XBGF3.Leaf('to', convert(nc1, nc2, nt))) s.addParam(n) xbgf.addStep(s) ET.ElementTree(xbgf.getXml()).write(sys.argv[4]) sys.exit(0)
nts = [] for p in g.prods: if p.expr.wrapped: for n in p.expr.wrapped.getXml().findall('.//nonterminal'): if (n.text not in nts) and (n.text != p.nt): nts.append(n.text) return nts if __name__ == "__main__": if len(sys.argv) != 2: print('This tool presents an overview of a BGF file.') print('Usage:') print(' checkbgf <bgf>') sys.exit(1) grammar = BGF3.Grammar() grammar.parse(sys.argv[1]) print('<?xml version="1.0"?><xml>') wrap = lambda x, y: map(lambda z: '<' + x + '>' + z + '</' + x + '>', y) print((''.join(wrap('bottom', setminus(nrused(grammar), defd(grammar)))) + ''.join( wrap( 'top', setminus(setminus(defd(grammar), nrused(grammar)), grammar.roots)))).replace('&', '&')) terms = term(grammar) htmlify = lambda s: map( lambda x: x.replace('&', '&').replace('>', '>').replace( '<', '<'), s) print(''.join(wrap('keyword', htmlify(filter(isalpha, terms)))) + ''.join(wrap('terminal', htmlify(filter(isnotalpha, terms)))))
if str(e1.wrapped.__class__) == "<class 'BGF3.Terminal'>": if str(e2.wrapped.__class__) != "<class 'BGF3.Terminal'>": #print("--isEqualE--> NO (type mismatch)") return False return e1.wrapped.data == e2.wrapped.data print(str(e1.wrapped.__class__)) #print("--isEqualE--> NO") return False def isEqualNT(n1, n2): # all NTs are equal #print('isEqualNT(%s,%s)' % (n1,n2)) #print("--isEqualNT--> YES") return True if __name__ == "__main__": if len(sys.argv) != 3: print('Usage:') print(' name-independent-differ.py input1.bgf input2.bgf') sys.exit(-1) g1 = BGF3.Grammar() g1.parse(sys.argv[1]) g2 = BGF3.Grammar() g2.parse(sys.argv[2]) if isEqualG(g1, g2): sys.exit(0) else: sys.exit(-1)
import os, sys import xml.etree.ElementTree as ET sys.path.append(os.getcwd().split('slps')[0] + 'slps/shared/python') import BGF3 from functools import reduce if __name__ == "__main__": if len(sys.argv) < 4: print('Usage:') print(' merge.py input1.bgf [inputX.bgf ...] output.bgf') sys.exit(-1) bgfs = [] names = [] nts = [] for fname in sys.argv[1:-1]: g = BGF3.Grammar() g.parse(fname) bgfs.append(g) names.append(fname) print(len(bgfs), 'grammars read.') for i in range(0, len(bgfs)): n = [] for p in bgfs[i].prods: if p.nt not in n: n.append(p.nt) nts.append(n) print('\t', names[i], 'has', len(bgfs[i].prods), 'productions,', len(nts[i]), 'nonterminals and', len(bgfs[i].roots), 'roots') # FINAL STEP: compose BGF allbgf = BGF3.Grammar() # roots are combined