Match compiler: Turn code into a python class
This will make passing around internal states a lot easier
This commit is contained in:
parent
7f0bc73e8e
commit
71a236b3df
|
@ -3,7 +3,11 @@
|
|||
import re
|
||||
import glob
|
||||
|
||||
def insertMatchStr(matchStrs, look_for):
|
||||
class MatchCompiler:
|
||||
def __init__(self):
|
||||
self._selftests()
|
||||
|
||||
def _insertMatchStr(self, matchStrs, look_for):
|
||||
prefix = 'matchStr'
|
||||
|
||||
# Add entry if needed
|
||||
|
@ -13,7 +17,7 @@ def insertMatchStr(matchStrs, look_for):
|
|||
|
||||
return prefix + str(matchStrs[look_for])
|
||||
|
||||
def compileCmd(tok, matchStrs):
|
||||
def _compileCmd(self, tok, matchStrs):
|
||||
if tok == '%any%':
|
||||
return 'true'
|
||||
elif tok == '%bool%':
|
||||
|
@ -27,13 +31,13 @@ def compileCmd(tok, matchStrs):
|
|||
elif tok == '%op%':
|
||||
return 'tok->isOp()'
|
||||
elif tok == '%or%':
|
||||
return '(tok->str()==' + insertMatchStr(matchStrs, '|') + ')/* | */'
|
||||
return '(tok->str()==' + self._insertMatchStr(matchStrs, '|') + ')/* | */'
|
||||
elif tok == '%oror%':
|
||||
return '(tok->str()==' + insertMatchStr(matchStrs, '||') + ')/* || */'
|
||||
return '(tok->str()==' + self._insertMatchStr(matchStrs, '||') + ')/* || */'
|
||||
elif tok == '%str%':
|
||||
return '(tok->type()==Token::eString)'
|
||||
elif tok == '%type%':
|
||||
return '(tok->isName() && tok->varId()==0U && tok->str() != ' + insertMatchStr(matchStrs, 'delete') + '/* delete */)'
|
||||
return '(tok->isName() && tok->varId()==0U && tok->str() != ' + self._insertMatchStr(matchStrs, 'delete') + '/* delete */)'
|
||||
elif tok == '%var%':
|
||||
return 'tok->isName()'
|
||||
elif tok == '%varid%':
|
||||
|
@ -41,9 +45,9 @@ def compileCmd(tok, matchStrs):
|
|||
elif (len(tok)>2) and (tok[0]=="%"):
|
||||
print ("unhandled:" + tok)
|
||||
|
||||
return '(tok->str()==' + insertMatchStr(matchStrs, tok) + ')/* ' + tok + ' */'
|
||||
return '(tok->str()==' + self._insertMatchStr(matchStrs, tok) + ')/* ' + tok + ' */'
|
||||
|
||||
def compilePattern(matchStrs, pattern, nr, varid, isFindMatch=False):
|
||||
def _compilePattern(self, matchStrs, pattern, nr, varid, isFindMatch=False):
|
||||
ret = ''
|
||||
returnStatement = ''
|
||||
|
||||
|
@ -99,7 +103,7 @@ def compilePattern(matchStrs, pattern, nr, varid, isFindMatch=False):
|
|||
if not first:
|
||||
ret += logicalOp
|
||||
first = False
|
||||
ret += neg + compileCmd(tok2, matchStrs)
|
||||
ret += neg + self._compileCmd(tok2, matchStrs)
|
||||
|
||||
if "" in tokens2:
|
||||
ret += '))\n'
|
||||
|
@ -111,12 +115,12 @@ def compilePattern(matchStrs, pattern, nr, varid, isFindMatch=False):
|
|||
|
||||
# !!a
|
||||
elif tok[0:2]=="!!":
|
||||
ret += ' if (tok && tok->str() == ' + insertMatchStr(matchStrs, tok[2:]) + ')/* ' + tok[2:] + ' */\n'
|
||||
ret += ' if (tok && tok->str() == ' + self._insertMatchStr(matchStrs, tok[2:]) + ')/* ' + tok[2:] + ' */\n'
|
||||
ret += ' ' + returnStatement
|
||||
gotoNextToken = ' tok = tok ? tok->next() : NULL;\n'
|
||||
|
||||
else:
|
||||
ret += ' if (!tok || !' + compileCmd(tok, matchStrs) + ')\n'
|
||||
ret += ' if (!tok || !' + self._compileCmd(tok, matchStrs) + ')\n'
|
||||
ret += ' ' + returnStatement
|
||||
|
||||
if isFindMatch:
|
||||
|
@ -127,7 +131,7 @@ def compilePattern(matchStrs, pattern, nr, varid, isFindMatch=False):
|
|||
|
||||
return ret
|
||||
|
||||
def compileFindPattern(matchFunctions, matchStrs, pattern, findmatchnr, endToken, varId):
|
||||
def _compileFindPattern(self, matchFunctions, matchStrs, pattern, findmatchnr, endToken, varId):
|
||||
more_args = ''
|
||||
endCondition = ''
|
||||
if endToken:
|
||||
|
@ -140,13 +144,13 @@ def compileFindPattern(matchFunctions, matchStrs, pattern, findmatchnr, endToken
|
|||
ret += 'static const Token *findmatch' + str(findmatchnr) + '(const Token *start_tok'+more_args+') {\n'
|
||||
ret += ' for (; start_tok' + endCondition + '; start_tok = start_tok->next()) {\n'
|
||||
|
||||
ret += compilePattern(matchStrs, pattern, -1, varId, True)
|
||||
ret += self._compilePattern(matchStrs, pattern, -1, varId, True)
|
||||
ret += ' }\n'
|
||||
ret += ' return NULL;\n}\n'
|
||||
|
||||
return ret
|
||||
|
||||
def parseMatch(line, pos1):
|
||||
def parseMatch(self, line, pos1):
|
||||
parlevel = 0
|
||||
args = []
|
||||
argstart = 0
|
||||
|
@ -180,7 +184,7 @@ def parseMatch(line, pos1):
|
|||
|
||||
return None
|
||||
|
||||
def parseStringComparison(line, pos1):
|
||||
def _parseStringComparison(self, line, pos1):
|
||||
startPos = 0
|
||||
endPos = 0
|
||||
pos = pos1
|
||||
|
@ -200,7 +204,7 @@ def parseStringComparison(line, pos1):
|
|||
|
||||
return None
|
||||
|
||||
def replaceTokenMatch(matchFunctions, matchStrs, line):
|
||||
def _replaceTokenMatch(self, matchFunctions, matchStrs, line):
|
||||
while True:
|
||||
pos1 = line.find('Token::Match(')
|
||||
if pos1 == -1:
|
||||
|
@ -208,7 +212,7 @@ def replaceTokenMatch(matchFunctions, matchStrs, line):
|
|||
if pos1 == -1:
|
||||
break
|
||||
|
||||
res = parseMatch(line, pos1)
|
||||
res = self.parseMatch(line, pos1)
|
||||
if res == None:
|
||||
break
|
||||
else:
|
||||
|
@ -231,11 +235,11 @@ def replaceTokenMatch(matchFunctions, matchStrs, line):
|
|||
a3 = ',' + arg3
|
||||
patternNumber = len(matchFunctions) + 1
|
||||
line = line[:pos1]+'match'+str(patternNumber)+'('+arg1+a3+')'+line[pos1+len(g0):]
|
||||
matchFunctions.append(compilePattern(matchStrs, arg2, patternNumber, arg3))
|
||||
matchFunctions.append(self._compilePattern(matchStrs, arg2, patternNumber, arg3))
|
||||
|
||||
return line
|
||||
|
||||
def replaceTokenFindMatch(matchFunctions, matchStrs, line):
|
||||
def _replaceTokenFindMatch(self, matchFunctions, matchStrs, line):
|
||||
pos1 = 0
|
||||
while True:
|
||||
is_findmatch = False
|
||||
|
@ -246,7 +250,7 @@ def replaceTokenFindMatch(matchFunctions, matchStrs, line):
|
|||
if pos1 == -1:
|
||||
break
|
||||
|
||||
res = parseMatch(line, pos1)
|
||||
res = self.parseMatch(line, pos1)
|
||||
if res == None:
|
||||
break
|
||||
else:
|
||||
|
@ -291,11 +295,11 @@ def replaceTokenFindMatch(matchFunctions, matchStrs, line):
|
|||
a3 += ',' + varId
|
||||
findMatchNumber = len(matchFunctions) + 1
|
||||
line = line[:pos1]+'findmatch'+str(findMatchNumber)+'('+arg1+a3+')'+line[pos1+len(g0):]
|
||||
matchFunctions.append(compileFindPattern(matchFunctions, matchStrs, pattern, findMatchNumber, endToken, varId))
|
||||
matchFunctions.append(self._compileFindPattern(matchFunctions, matchStrs, pattern, findMatchNumber, endToken, varId))
|
||||
|
||||
return line
|
||||
|
||||
def replaceCStrings(matchStrs, line):
|
||||
def _replaceCStrings(self, matchStrs, line):
|
||||
while True:
|
||||
match = re.search('str\(\) (==|!=) "', line)
|
||||
if not match:
|
||||
|
@ -303,18 +307,18 @@ def replaceCStrings(matchStrs, line):
|
|||
if not match:
|
||||
break
|
||||
|
||||
res = parseStringComparison(line, match.start())
|
||||
res = self._parseStringComparison(line, match.start())
|
||||
if res == None:
|
||||
break
|
||||
|
||||
startPos = res[0]
|
||||
endPos = res[1]
|
||||
text = line[startPos+1:endPos-1]
|
||||
line = line[:startPos] + insertMatchStr(matchStrs, text) + line[endPos:]
|
||||
line = line[:startPos] + self._insertMatchStr(matchStrs, text) + line[endPos:]
|
||||
|
||||
return line
|
||||
|
||||
def convertFile(srcname, destname):
|
||||
def convertFile(self, srcname, destname):
|
||||
fin = open(srcname, "rt")
|
||||
srclines = fin.readlines()
|
||||
fin.close()
|
||||
|
@ -329,14 +333,14 @@ def convertFile(srcname, destname):
|
|||
matchStrs = {}
|
||||
for line in srclines:
|
||||
# Compile Token::Match and Token::simpleMatch
|
||||
line = replaceTokenMatch(matchFunctions, matchStrs, line)
|
||||
line = self._replaceTokenMatch(matchFunctions, matchStrs, line)
|
||||
|
||||
# Compile Token::findsimplematch
|
||||
# NOTE: Not enabled for now since the generated code is slower than before.
|
||||
# line = replaceTokenFindMatch(matchFunctions, matchStrs, line)
|
||||
# line = self._replaceTokenFindMatch(matchFunctions, matchStrs, line)
|
||||
|
||||
# Cache plain C-strings in C++ strings
|
||||
line = replaceCStrings(matchStrs, line)
|
||||
line = self._replaceCStrings(matchStrs, line)
|
||||
|
||||
code += line
|
||||
|
||||
|
@ -354,18 +358,23 @@ def convertFile(srcname, destname):
|
|||
fout.write(header+stringList+strFunctions+code)
|
||||
fout.close()
|
||||
|
||||
# selftests..
|
||||
def assertEquals(actual,expected):
|
||||
def _assertEquals(self,actual,expected):
|
||||
if actual!=expected:
|
||||
print ('Assertion failed:')
|
||||
print (actual)
|
||||
print (expected)
|
||||
assert actual == expected
|
||||
assertEquals(parseMatch(' Token::Match(tok, ";") ',2), ['Token::Match(tok, ";")','tok',' ";"'])
|
||||
assertEquals(parseMatch(' Token::Match(tok,', 2), None) # multiline Token::Match is not supported yet
|
||||
assertEquals(parseMatch(' Token::Match(Token::findsimplematch(tok,")"), ";")', 2), ['Token::Match(Token::findsimplematch(tok,")"), ";")', 'Token::findsimplematch(tok,")")', ' ";"']) # inner function call
|
||||
|
||||
def _selftests(self):
|
||||
self._assertEquals(self.parseMatch(' Token::Match(tok, ";") ',2), ['Token::Match(tok, ";")','tok',' ";"'])
|
||||
self._assertEquals(self.parseMatch(' Token::Match(tok,', 2), None) # multiline Token::Match is not supported yet
|
||||
self._assertEquals(self.parseMatch(' Token::Match(Token::findsimplematch(tok,")"), ";")', 2), ['Token::Match(Token::findsimplematch(tok,")"), ";")', 'Token::findsimplematch(tok,")")', ' ";"']) # inner function call
|
||||
|
||||
|
||||
# Main program
|
||||
mc = MatchCompiler()
|
||||
|
||||
# convert all lib/*.cpp files
|
||||
for f in glob.glob('lib/*.cpp'):
|
||||
print (f + ' => build/' + f[4:])
|
||||
convertFile(f, 'build/'+f[4:])
|
||||
mc.convertFile(f, 'build/'+f[4:])
|
||||
|
|
Loading…
Reference in New Issue