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 cstring_ = Keyword("cstring") 77 switch_ = Keyword("switch") 78 default_ = Keyword("default") 79 case_ = Keyword("case") 80 81 identifier = Word( alphas, alphanums + "_" ) 82 enumname = Word( alphanums + "_" ) 83 84 integer = ( Combine( CaselessLiteral("0x") + Word( nums+"abcdefABCDEF" ) ) | 85 Word( nums+"+-", nums ) ).setName("int").setParseAction(cvtInt) 86 87 typename = identifier.copy().setParseAction(lambda toks : ptypes.TypeRef(str(toks[0]))) 88 89 # This is just normal "types", i.e. not channels or messages 90 typeSpec = Forward() 91 92 attributeValue = integer ^ identifier 93 attribute = Group(Combine ("@" + identifier) + Optional(lparen + delimitedList(attributeValue) + rparen)) 94 attributes = Group(ZeroOrMore(attribute)) 95 arraySizeSpecImage = Group(image_size_ + lparen + integer + comma + identifier + comma + identifier + rparen) 96 arraySizeSpecCString = Group(cstring_ + lparen + rparen) 97 arraySizeSpec = lbrack + Optional(identifier ^ integer ^ arraySizeSpecImage ^ arraySizeSpecCString, default="") + rbrack 98 variableDef = Group(typeSpec + Optional("*", default=None) + identifier + Optional(arraySizeSpec, default=None) + attributes - semi) \ 99 .setParseAction(parseVariableDef) 100 101 switchCase = Group(Group(OneOrMore(default_.setParseAction(replaceWith(None)) + colon | Group(case_.suppress() + Optional("!", default="") + identifier) + colon)) + variableDef) \ 102 .setParseAction(lambda toks: ptypes.SwitchCase(toks[0][0], toks[0][1])) 103 switchBody = Group(switch_ + lparen + delimitedList(identifier,delim='.', combine=True) + rparen + lbrace + Group(OneOrMore(switchCase)) + rbrace + identifier + attributes - semi) \ 104 .setParseAction(lambda toks: ptypes.Switch(toks[0][1], toks[0][2], toks[0][3], toks[0][4])) 105 messageBody = structBody = Group(lbrace + ZeroOrMore(variableDef | switchBody) + rbrace) 106 structSpec = Group(struct_ + identifier + structBody + attributes).setParseAction(lambda toks: ptypes.StructType(toks[0][1], toks[0][2], toks[0][3])) 107 108 # have to use longest match for type, in case a user-defined type name starts with a keyword type, like "channel_type" 109 typeSpec << ( structSpec ^ int8_ ^ uint8_ ^ int16_ ^ uint16_ ^ 110 int32_ ^ uint32_ ^ int64_ ^ uint64_ ^ unix_fd_ ^ 111 typename).setName("type") 112 113 flagsBody = enumBody = Group(lbrace + delimitedList(Group (enumname + Optional(equals + integer, default=None) + attributes)) + Optional(comma) + rbrace) 114 115 messageSpec = Group(message_ + messageBody + attributes).setParseAction(lambda toks: ptypes.MessageType(None, toks[0][1], toks[0][2])) | typename 116 117 channelParent = Optional(colon + typename, default=None) 118 channelMessage = Group(messageSpec + identifier + Optional(equals + integer, default=None) + semi) \ 119 .setParseAction(lambda toks: ptypes.ChannelMember(toks[0][1], toks[0][0], toks[0][2])) 120 channelBody = channelParent + Group(lbrace + ZeroOrMore( server_ + colon | client_ + colon | channelMessage) + rbrace) 121 122 enum_ = (enum32_ | enum16_ | enum8_) 123 flags_ = (flags32_ | flags16_ | flags8_) 124 enumDef = Group(enum_ + identifier + enumBody + attributes - semi).setParseAction(lambda toks: ptypes.EnumType(toks[0][0], toks[0][1], toks[0][2], toks[0][3])) 125 flagsDef = Group(flags_ + identifier + flagsBody + attributes - semi).setParseAction(lambda toks: ptypes.FlagsType(toks[0][0], toks[0][1], toks[0][2], toks[0][3])) 126 messageDef = Group(message_ + identifier + messageBody + attributes - semi).setParseAction(lambda toks: ptypes.MessageType(toks[0][1], toks[0][2], toks[0][3])) 127 channelDef = Group(channel_ + identifier + channelBody + attributes - semi).setParseAction(lambda toks: ptypes.ChannelType(toks[0][1], toks[0][2], toks[0][3], toks[0][4])) 128 structDef = Group(struct_ + identifier + structBody + attributes - semi).setParseAction(lambda toks: ptypes.StructType(toks[0][1], toks[0][2], toks[0][3])) 129 typedefDef = Group(typedef_ + identifier + typeSpec + attributes - semi).setParseAction(lambda toks: ptypes.TypeAlias(toks[0][1], toks[0][2], toks[0][3])) 130 131 definitions = typedefDef | structDef | enumDef | flagsDef | messageDef | channelDef 132 133 protocolChannel = Group(typename + identifier + Optional(equals + integer, default=None) + semi) \ 134 .setParseAction(lambda toks: ptypes.ProtocolMember(toks[0][1], toks[0][0], toks[0][2])) 135 protocolDef = Group(protocol_ + identifier + Group(lbrace + ZeroOrMore(protocolChannel) + rbrace) + semi) \ 136 .setParseAction(lambda toks: ptypes.ProtocolType(toks[0][1], toks[0][2])) 137 138 bnf = ZeroOrMore (definitions) + protocolDef + StringEnd() 139 140 singleLineComment = "//" + restOfLine 141 bnf.ignore( singleLineComment ) 142 bnf.ignore( cStyleComment ) 143 144 return bnf 145 146 147def parse(filename): 148 try: 149 bnf = SPICE_BNF() 150 types = bnf.parseFile(filename) 151 except ParseException as err: 152 six.print_(err.line, file=sys.stderr) 153 six.print_(" "*(err.column-1) + "^", file=sys.stderr) 154 six.print_(err, file=sys.stderr) 155 return None 156 157 for t in types: 158 t.resolve() 159 t.register() 160 protocol = types[-1] 161 return protocol 162