Hi,
I am currently redesign my old compiler written in python by the use of
pyl. The current code is attached.
First I want to explain the goal:
This compiler should create an AST which is used to translate a domain
specific language in to some kind of assembler. Actual there are two
elements given in the grammar:
1.) a comment
2.) global variable declaration
The global variable declaration can contain a list of variables. It is also
allowed to write comments. A listing of the text can look like this:
"""
// comment 1
global {
// comment 2
integer a;
integer a[2345];
// comment 3
}
"""
I have some problems by defining the grammar rules. I give a short pseudo
listing:
start :
| startElement
| start startElement
startElement : comment
startElement : global { varList }
varList :
| varListElement
| varList varListElement
varListElement : comment
varListElement : type name ;
varListElement: type name [ number ] ;
As you can see it is very simple. I did not understand the error (4 Shift /
Reduce Erros). Maybe you can help me.
Thanks and have a nice weekend!
Stefan
--
You received this message because you are subscribed to the Google Groups
"ply-hack" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/ply-hack/559b5ca0-7f7c-4bf5-9711-581add0d035d%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
'''
Created on 20.08.2013
@author: StJ
'''
import argparse
import sys
import os
import ply.lex as lex
import ply.yacc as yacc
import ctypes
import struct
import re
import copy
import subprocess
import logging
import exceptions
#import APDB
# some global data
# a dict associate the functionID with the name and the list with parameters
gHALfidD = {
None : ('unknown function', [])
}
# a dict associate the variableID with a name
gHALvidD = {
None : ('unknown variable type',)
}
# a dict with all basic i/o types
# data = (name, c type, endianness)
gBasicIOTypesD = {
None : ('unknown basic i/o type', None, None)
}
# a dict mapping c types to python types
gCTypeToPythonD = {
'int' : int,
'uint32_t' : int,
'int32_t' : int,
'raw' : int,
'char' : int,
'float' : float,
}
# the basic AST class object
class ASTobject(object):
def __init__(self, line ,column):
self.line = line
self.column = column
def __repr__ (self):
return 'line:{line} column:{column}'.format(line=self.line,column=self.column)
# the basic AST comment class
class ASTcomment (ASTobject):
def __init__(self, line, column, comment):
super(ASTcomment, self).__init__(line ,column)
self.comment = comment
def __repr__ (self):
return 'comment: "{comment}" at {pos}'.format(typeName=self.comment,pos=super(ASTobject,self).__repr__())
# the AST object for type defs
class ASTtypedef (ASTobject):
def __init__(self, line ,column, typeName, typedefASTInstrL):
super(ASTtypedef, self).__init__(line ,column)
self.typeName = typeName
self.typedefASTInstrL = typedefASTInstrL
def __repr__ (self):
return 'typedef of "{typeName}" at {pos}'.format(typeName=self.typeName,pos=super(ASTobject,self).__repr__())
# the AST object for subvalue defs at type defs
class ASTtypedefInstr(ASTobject):
def __init__(self, line ,column, subName, typeName):
super(ASTtypedefInstr, self).__init__(line ,column)
self.subName = subName
self.typeName = typeName
def __repr__ (self):
return 'subvalue typedef of "{name}" from type "{type}" at {pos}'.format(name=self.subName,type=self.typeName, pos=super(ASTobject,self).__repr__())
# the AST type for a variable declaration
class ASTvariableDef(ASTobject):
def __init__(self, line ,column, varName, varType, amount):
super(ASTvariableDef, self).__init__(line ,column)
self.varName = varName
self.varType = varType
self.amount = amount
def __repr__ (self):
return 'variable name:"{name}" with type:"{type}" and an amount of {amount} at {pos}'.format(name=self.subName,type=self.typeName,amount=self.amount, pos=super(ASTobject,self).__repr__())
# the AST type for function parameters
class ASTfuncParameter(ASTobject):
def __init__(self, line ,column, varName, varType, ioType):
super(ASTfuncParameter, self).__init__(line ,column)
self.varName = varName
self.varType = varType
self.ioType = ioType
def __repr__ (self):
return 'function parameter name:"{name}" with type:"{type}" i/o:{io} at {pos}'.format(name=self.varName,type=self.varType,io=self.ioType, pos=super(ASTobject,self).__repr__())
class ASTinstructionParamConst (ASTobject):
def __init__(self, line, column, Const, ConstType):
super(ASTinstructionParamConst, self).__init__(line ,column)
self.const = Const
self.constType = ConstType
def __repr__ (self):
return 'const. instrParam value:"{const}" type:"{type}" at {pos}'.format(const=self.const,type=self.constType, pos=super(ASTobject,self).__repr__())
class ASTinstructionParamRefVar (ASTobject):
def __init__(self, line, column, varRef, subValueRefList = [], index = 0):
super(ASTinstructionParamRefVar, self).__init__(line ,column)
self.varRef = varRef
self.subValueRefList = subValueRefList
self.index = index
def __repr__ (self):
refStr = ''
for r in self.subValueRefList:
refStr += '.'+ r
return 'ref.Var. instrParam to variable:"{varRef}{refStr}[{index}]" at {pos}'.format(const=self.varRef,refStr=refStr, index=self.index, pos=super(ASTobject,self).__repr__())
def addSubValue(self, sv):
self.subValueRefList.append(sv)
def setIndex (self, indx):
self.index = indx
# the AST type for an instruction
class ASTinstruction(ASTobject):
def __init__(self, line ,column, instrID, instrParamsL):
super(ASTinstruction, self).__init__(line ,column)
self.instrID = instrID
self.instrParamsL = instrParamsL
def __repr__ (self):
paramLstr = ''
j = 0
for i in self.instrParamsL:
if j != 0:
paramLstr += ', '
paramLstr += str(i)
j+=1
return 'instr.: {name}({params}) at {pos}'.format(name=gHALfidD[self.instrID][0],params=paramLstr, pos=super(ASTobject,self).__repr__())
# the AST type for an instruction
class ASTConditionalBlock(ASTinstruction):
def __init__(self, line, column, condInstrList, TrueCode, FalseCode, loopFlag, loopExtraCode):
super(ASTConditionalBlock, self).__init__(line ,column)
self.condInstrList = condInstrList
self.TrueCode = TrueCode
self.FalseCode = FalseCode
self.loopFlag = loopFlag
self.loopExtraCode = loopExtraCode
def __repr__ (self):
return 'condition block at {pos}'.format(pos=super(ASTobject,self).__repr__())
# the AST type for an function call
class ASTinstructionFunctionCall(ASTinstruction):
def __init__(self, line ,column, functionName, outputL, inputL):
super(ASTinstructionFunctionCall, self).__init__(line ,column)
self.functionName = functionName
self.outputL = outputL
self.inputL = inputL
def __repr__ (self):
paramLstr = '['
j = 0
for i in self.outputL:
if j != 0:
paramLstr += ', '
paramLstr += str(i)
j+=1
paramLstr += '] {callF} ['.format(callF=self.functionName)
j = 0
for i in self.inputL:
if j != 0:
paramLstr += ', '
paramLstr += str(i)
j+=1
paramLstr += '] at {pos}'.format(pos=super(ASTobject,self).__repr__())
return paramLstr
# the AST type for an function call
class ASTvariableOperation(ASTinstruction):
def __init__(self, line ,column, varOpName, ParamDict):
super(ASTvariableOperation, self).__init__(line ,column)
self.varOpName = varOpName
self.ParamDict = ParamDict
def __repr__ (self):
paramLstr = '{varOpName} ['.format(varOpName=self.varOpName)
i = 0
for key, val in self.ParamDict.items():
if (i != 0):
paramLstr += ', '
paramLstr += '{key}={val}'.format(key=key, val=val)
i += 1
paramLstr += '] at {pos}'.format(pos=super(ASTobject,self).__repr__())
return paramLstr
class ASTexpression(ASTobject):
def __init__(self, line ,column, expType, expParamL):
super(ASTexpression, self).__init__(line ,column)
self.expType = expType
self.expParamL = expParamL
def __repr__ (self):
paramLstr = 'expression {expType} on'.format(expType=self.expType)
j = 0
for e in self.expParamL:
if j != 0:
paramLstr += ' with '
paramLstr += str(e)
j+=1
paramLstr += ' at {pos}'.format(pos=super(ASTobject,self).__repr__())
return paramLstr
# the AST type for functions
class ASTfunction(ASTobject):
def __init__(self, line ,column, fname, inpOutpL, localVarL, instructionL):
super(ASTfunction, self).__init__(line ,column)
self.fname = fname
self.inpOutpL = inpOutpL
self.localVarL = localVarL
self.instructionL = instructionL
def __repr__ (self):
rStr = 'function definition of "{fname}" at {pos}'.format(fname=self.fname, pos=super(ASTobject,self).__repr__())
rStr += '\n=========================================='
rStr += '\nInputs / Outputs:'
for e in self.inpOutpL:
rStr += '\n\t{io}'.format(io=e)
rStr = '\nLocal variables:'
for e in self.localVarL:
rStr += '\n\t{v}'.format(v=e)
rStr = '\ninstructions:'
for e in self.instructionL:
rStr += '\n\t{instr}'.format(instr=e)
rStr += '\n=========================================='
# the AST type for functions
class ASTmain(ASTobject):
def __init__(self, line ,column, mainName, localVarL, instructionL):
super(ASTmain, self).__init__(line ,column)
self.mainName = mainName
self.localVarL = localVarL
self.instructionL = instructionL
def __repr__ (self):
rStr = 'main function definition of "{mainName}" at {pos}'.format(mainName=self.mainName, pos=super(ASTobject,self).__repr__())
rStr += '\n=========================================='
rStr = '\nLocal variables:'
for e in self.localVarL:
rStr += '\n\t{v}'.format(v=e)
rStr = '\ninstructions:'
for e in self.instructionL:
rStr += '\n\t{instr}'.format(instr=e)
rStr += '\n=========================================='
# setup
# def setup():
# logging.info ('setup')
# logging.info ('open database')
# db = APDB.APDB('APdbCreate.sql','dbInit.xml')
#
# logging.info ('populate basic i/o type list')
# dbBIOL = db.HAL_basicIOTypes_getList()
# for (idHAL_IOTypesDefinition, TypeID, TypeName, description, cType, endianType, sizeInBytes) in dbBIOL:
# gBasicIOTypesD[TypeID] = (TypeName, cType, endianType)
#
# logging.info ('populate function HAL list')
# dbfL = db.HAL_DefFunctions_getList()
# for (fuuid, fid, fname, fdescr) in dbfL:
# dbfpL = db.HAL_DefFunctions_getParamList(fid)
# fpL = []
# for (idHAL_FunctionsParameter, pfid, name, descr, idParameterClass, idParameterType) in dbfpL:
# fpL.append((name, idParameterClass, idParameterType))
# gHALfidD[fid] = (fname, fpL)
#
# logging.info ('populate variable HAL list')
# dbvL = db.HAL_VariableDefinition_getList()
# for (idHAL_VariableDefinition, VariableID, varName, description) in dbvL:
# gHALvidD[VariableID] = (varName,)
# logging.info ('setup finished')
# ==========================================================
# lets create the tokenizer
# ==========================================================
reserved = {
'typedef' : 'typedef',
'global' : 'global',
'local' : 'local',
'code' : 'code',
'function' : 'function',
'interface' : 'interface',
'main' : 'main',
'if' : 'if',
'else' : 'else',
'for' : 'for',
'while' : 'while',
'checkButtonPressed': 'checkButtonPressed',
'update' : 'update',
}
tokens = [
'lBrace',
'rBrace',
'lSoftBrace',
'rSoftBrace',
'lBracket',
'rBracket',
'comma',
'semicolon',
'name',
'iNumber',
'fNumber',
'arrowLeft',
'arrowRight',
'not',
'add',
'sub',
'mul',
'div',
'nEqual',
'equal',
'assign',
'comment',
'less',
'lessEqual',
'more',
'moreEqual',
'inc',
'dec',
'string',
'addAssign',
'point'
] + list(reserved.values())
t_lBrace = '{'
t_rBrace = '}'
t_lSoftBrace = '\('
t_rSoftBrace = '\)'
t_lBracket = '\['
t_rBracket = '\]'
t_nEqual = '!='
t_equal = '=='
t_assign = '='
t_comma = ','
t_semicolon = ';'
t_ignore = ' \t'
t_arrowLeft = '>>'
t_arrowRight = '<<'
t_not = '!'
t_div = '/'
t_mul = '\*'
t_lessEqual = '<='
t_less = '<'
t_moreEqual = '>='
t_more = '>'
t_inc = '\+\+'
t_add = '\+'
t_dec = '--'
t_sub = '-'
t_addAssign = '\+='
t_point = '\.'
def t_comment (t):
r'(/\*(.|\n)*?\*/)|(//.*)'
t.type = 'comment'
l = len(t.value)
if (t.value[0:2] == '//') :
t.value = t.value[2:l]
else :
t.value = t.value[2:l-2]
return t
def t_string (t):
r'\"([^\\\n]|(\\.))*?\"'
return t
def t_name(t):
r'[a-zA-Z_][a-zA-Z0-9_]*'
t.type = reserved.get(t.value,'name') # Check for reserved words
return t
def t_fNumber(t):
r'[-+]?\d+\.\d+([eE][-+]?\d+)?'
try:
t.value = float(t.value)
except ValueError:
print("Integer value too large %d", t.value)
t.value = 0
return t
def t_iNumber(t):
r'[-+]?\d+'
try:
t.value = int(t.value)
except ValueError:
print("Integer value too large %d", t.value)
t.value = 0
return t
# Define a rule so we can track line numbers
def t_newline(t):
r'\n+'
t.lexer.lineno += len(t.value)
def t_error(t):
print("Illegal character '%s'" % t.value[0])
t.lexer.skip(1)
# =====================================================
# the parser
# =====================================================
# Parsing rules
def p_startElements(p):
"""start :
| startEle
| start startEle"""
def p_startComment (p):
'startEle : comment'
p[0] = ASTcomment (p.lineno(1) ,p.lexpos(1), p[1])
def p_startGlobVar(p):
'startEle : global lBrace varDeclList rBrace'
p[0] = p[3]
def p_varDecl_Easy(p):
'varDecl : name name semicolon'
pass
def p_varDecl_Amount(p):
'varDecl : name name lBracket iNumber rBracket semicolon'
pass
def p_varDecl_Comment(p):
'varDecl : comment'
pass
def p_varDecl_list(p):
"""varDeclList :
| varDecl
| varDeclList varDecl"""
pass
# error rule
def p_error(p):
text = 'Syntax error at Line: {line} pos: {pos}'.format(line= p.lineno, pos=p.lexpos)
raise exceptions.SyntaxError(text)
# reads a textfile into a buffer and return it
def readFile (filename):
logging.info ('try to open file "{fn}"'.format(fn=filename))
file = open(filename, 'r')
logging.info ('read data')
text = file.read()
logging.info ('close file')
file.close()
return text
def main(argv):
parser = argparse.ArgumentParser(description='the audio language compiler v. 0.2')
parser.add_argument('-i', help='the audio language code input file')
parser.add_argument('-o', help='the audio language assembler output dir', default=os.curdir)
args = parser.parse_args()
return (args.i, args.o)
if __name__ == '__main__':
# setup logger
logging.basicConfig(filename='ALClog.txt',filemode='w',format='%(name)s [%(levelname)s] : %(message)s',level=logging.DEBUG)
logging.info ('start logger')
# get cmdline arguments
(iFile, oDir) = main(sys.argv[1:])
# setup compiler
#setup()
# read AL file
# try:
# ALtxt = readFile(iFile)
ALtxt = """
// comment 1
global {
// comment 2
integer a;
integer a[2345];
// comment 3
}
"""
# create lexer
lexer = lex.lex()
lexer.input(ALtxt)
p = yacc.yacc(
start='start',
debugfile='ALC2dbg.txt',
tabmodule='ALC2tab.txt'
)
res = p.parse(ALtxt,lexer=lexer)
print res
# except IOError as e:
# print "I/O error({0}): {1}".format(e.errno, e.strerror)
# except ValueError:
# print "Could not convert data to an integer."
# except TypeError as te:
# print "type error "+str(te)
# except:
# print "Unexpected error:", sys.exc_info()[0]
# raise
pass