1import six 2 3try: 4 from pyparsing import Literal, CaselessLiteral, Word, OneOrMore, ZeroOrMore, \ 5 Forward, delimitedList, Group, Optional, Combine, alphas, nums, restOfLine, cStyleComment, \ 6 alphanums, ParseException, ParseResults, Keyword, StringEnd, replaceWith 7except ImportError: 8 six.print_("Module pyparsing not found.") 9 exit(1) 10 11 12from . import ptypes 13import sys 14 15cvtInt = lambda toks: int(toks[0]) 16 17def parseVariableDef(toks): 18 t = toks[0][0] 19 pointer = toks[0][1] 20 name = toks[0][2] 21 array_size = toks[0][3] 22 attributes = toks[0][4] 23 24 if array_size != None: 25 t = ptypes.ArrayType(t, array_size) 26 27 if pointer != None: 28 t = ptypes.PointerType(t) 29 30 return ptypes.Member(name, t, attributes) 31 32bnf = None 33def SPICE_BNF(): 34 global bnf 35 36 if not bnf: 37 38 # punctuation 39 colon = Literal(":").suppress() 40 lbrace = Literal("{").suppress() 41 rbrace = Literal("}").suppress() 42 lbrack = Literal("[").suppress() 43 rbrack = Literal("]").suppress() 44 lparen = Literal("(").suppress() 45 rparen = Literal(")").suppress() 46 equals = Literal("=").suppress() 47 comma = Literal(",").suppress() 48 semi = Literal(";").suppress() 49 50 # primitive types 51 int8_ = Keyword("int8").setParseAction(replaceWith(ptypes.int8)) 52 uint8_ = Keyword("uint8").setParseAction(replaceWith(ptypes.uint8)) 53 int16_ = Keyword("int16").setParseAction(replaceWith(ptypes.int16)) 54 uint16_ = Keyword("uint16").setParseAction(replaceWith(ptypes.uint16)) 55 int32_ = Keyword("int32").setParseAction(replaceWith(ptypes.int32)) 56 uint32_ = Keyword("uint32").setParseAction(replaceWith(ptypes.uint32)) 57 int64_ = Keyword("int64").setParseAction(replaceWith(ptypes.int64)) 58 uint64_ = Keyword("uint64").setParseAction(replaceWith(ptypes.uint64)) 59 unix_fd_ = Keyword("unix_fd").setParseAction(replaceWith(ptypes.unix_fd)) 60 61 # keywords 62 enum32_ = Keyword("enum32").setParseAction(replaceWith(32)) 63 enum16_ = Keyword("enum16").setParseAction(replaceWith(16)) 64 enum8_ = Keyword("enum8").setParseAction(replaceWith(8)) 65 flags32_ = Keyword("flags32").setParseAction(replaceWith(32)) 66 flags16_ = Keyword("flags16").setParseAction(replaceWith(16)) 67 flags8_ = Keyword("flags8").setParseAction(replaceWith(8)) 68 channel_ = Keyword("channel") 69 server_ = Keyword("server") 70 client_ = Keyword("client") 71 protocol_ = Keyword("protocol") 72 typedef_ = Keyword("typedef") 73 struct_ = Keyword("struct") 74 message_ = Keyword("message") 75 image_size_ = Keyword("image_size") 76 bytes_ = Keyword("bytes") 77 cstring_ = Keyword("cstring") 78 switch_ = Keyword("switch") 79 default_ = Keyword("default") 80 case_ = Keyword("case") 81 82 identifier = Word( alphas, alphanums + "_" ) 83 enumname = Word( alphanums + "_" ) 84 85 integer = ( Combine( CaselessLiteral("0x") + Word( nums+"abcdefABCDEF" ) ) | 86 Word( nums+"+-", nums ) ).setName("int").setParseAction(cvtInt) 87 88 typename = identifier.copy().setParseAction(lambda toks : ptypes.TypeRef(str(toks[0]))) 89 90 # This is just normal "types", i.e. not channels or messages 91 typeSpec = Forward() 92 93 attributeValue = integer ^ identifier 94 attribute = Group(Combine ("@" + identifier) + Optional(lparen + delimitedList(attributeValue) + rparen)) 95 attributes = Group(ZeroOrMore(attribute)) 96 arraySizeSpecImage = Group(image_size_ + lparen + integer + comma + identifier + comma + identifier + rparen) 97 arraySizeSpecBytes = Group(bytes_ + lparen + identifier + comma + identifier + rparen) 98 arraySizeSpecCString = Group(cstring_ + lparen + rparen) 99 arraySizeSpec = lbrack + Optional(identifier ^ integer ^ arraySizeSpecImage ^ arraySizeSpecBytes ^arraySizeSpecCString, default="") + rbrack 100 variableDef = Group(typeSpec + Optional("*", default=None) + identifier + Optional(arraySizeSpec, default=None) + attributes - semi) \ 101 .setParseAction(parseVariableDef) 102 103 switchCase = Group(Group(OneOrMore(default_.setParseAction(replaceWith(None)) + colon | Group(case_.suppress() + Optional("!", default="") + identifier) + colon)) + variableDef) \ 104 .setParseAction(lambda toks: ptypes.SwitchCase(toks[0][0], toks[0][1])) 105 switchBody = Group(switch_ + lparen + delimitedList(identifier,delim='.', combine=True) + rparen + lbrace + Group(OneOrMore(switchCase)) + rbrace + identifier + attributes - semi) \ 106 .setParseAction(lambda toks: ptypes.Switch(toks[0][1], toks[0][2], toks[0][3], toks[0][4])) 107 messageBody = structBody = Group(lbrace + ZeroOrMore(variableDef | switchBody) + rbrace) 108 structSpec = Group(struct_ + identifier + structBody + attributes).setParseAction(lambda toks: ptypes.StructType(toks[0][1], toks[0][2], toks[0][3])) 109 110 # have to use longest match for type, in case a user-defined type name starts with a keyword type, like "channel_type" 111 typeSpec << ( structSpec ^ int8_ ^ uint8_ ^ int16_ ^ uint16_ ^ 112 int32_ ^ uint32_ ^ int64_ ^ uint64_ ^ unix_fd_ ^ 113 typename).setName("type") 114 115 flagsBody = enumBody = Group(lbrace + delimitedList(Group (enumname + Optional(equals + integer))) + Optional(comma) + rbrace) 116 117 messageSpec = Group(message_ + messageBody + attributes).setParseAction(lambda toks: ptypes.MessageType(None, toks[0][1], toks[0][2])) | typename 118 119 channelParent = Optional(colon + typename, default=None) 120 channelMessage = Group(messageSpec + identifier + Optional(equals + integer, default=None) + semi) \ 121 .setParseAction(lambda toks: ptypes.ChannelMember(toks[0][1], toks[0][0], toks[0][2])) 122 channelBody = channelParent + Group(lbrace + ZeroOrMore( server_ + colon | client_ + colon | channelMessage) + rbrace) 123 124 enum_ = (enum32_ | enum16_ | enum8_) 125 flags_ = (flags32_ | flags16_ | flags8_) 126 enumDef = Group(enum_ + identifier + enumBody + attributes - semi).setParseAction(lambda toks: ptypes.EnumType(toks[0][0], toks[0][1], toks[0][2], toks[0][3])) 127 flagsDef = Group(flags_ + identifier + flagsBody + attributes - semi).setParseAction(lambda toks: ptypes.FlagsType(toks[0][0], toks[0][1], toks[0][2], toks[0][3])) 128 messageDef = Group(message_ + identifier + messageBody + attributes - semi).setParseAction(lambda toks: ptypes.MessageType(toks[0][1], toks[0][2], toks[0][3])) 129 channelDef = Group(channel_ + identifier + channelBody + attributes - semi).setParseAction(lambda toks: ptypes.ChannelType(toks[0][1], toks[0][2], toks[0][3], toks[0][4])) 130 structDef = Group(struct_ + identifier + structBody + attributes - semi).setParseAction(lambda toks: ptypes.StructType(toks[0][1], toks[0][2], toks[0][3])) 131 typedefDef = Group(typedef_ + identifier + typeSpec + attributes - semi).setParseAction(lambda toks: ptypes.TypeAlias(toks[0][1], toks[0][2], toks[0][3])) 132 133 definitions = typedefDef | structDef | enumDef | flagsDef | messageDef | channelDef 134 135 protocolChannel = Group(typename + identifier + Optional(equals + integer, default=None) + semi) \ 136 .setParseAction(lambda toks: ptypes.ProtocolMember(toks[0][1], toks[0][0], toks[0][2])) 137 protocolDef = Group(protocol_ + identifier + Group(lbrace + ZeroOrMore(protocolChannel) + rbrace) + semi) \ 138 .setParseAction(lambda toks: ptypes.ProtocolType(toks[0][1], toks[0][2])) 139 140 bnf = ZeroOrMore (definitions) + protocolDef + StringEnd() 141 142 singleLineComment = "//" + restOfLine 143 bnf.ignore( singleLineComment ) 144 bnf.ignore( cStyleComment ) 145 146 return bnf 147 148 149def parse(filename): 150 try: 151 bnf = SPICE_BNF() 152 types = bnf.parseFile(filename) 153 except ParseException as err: 154 six.print_(err.line, file=sys.stderr) 155 six.print_(" "*(err.column-1) + "^", file=sys.stderr) 156 six.print_(err, file=sys.stderr) 157 return None 158 159 for t in types: 160 t.resolve() 161 t.register() 162 protocol = types[-1] 163 return protocol 164