ABNF parser generator

我在做一个H248协议的模拟器,首先要做的第一步工作是将H248消息解析出来。我在搜寻一种能够根据ABNF规范自动产生Parser代码的工具。网上有一个叫做APG的工具(http://www.coasttocoastresearch.com/),但是我输入H248协议的ABNF规范还是有错误,它给出的错误消息也很难看懂。不知道parser应该怎么写?用lex/yacc?这方面的知识很欠缺,需要好好学习以下:)

先把H248的ABNF规范写在这里

 

megacoMessage        = LWSP [authenticationHeader SEP ] message

authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON SequenceNum COLON AuthData

SecurityParmIndex    = "0x" 8(HEXDIG)
SequenceNum          = "0x" 8(HEXDIG)
AuthData             = "0x" 24*64(HEXDIG)

message = MegacopToken SLASH Version SEP mId SEP messageBody
messageBody          = ( errorDescriptor / transactionList )
transactionList      = 1*( transactionRequest / transactionReply / transactionPending / transactionResponseAck )
transactionPending   = PendingToken EQUAL TransactionID LBRKT RBRKT
transactionResponseAck = ResponseAckToken LBRKT transactionAck *(COMMA transactionAck) RBRKT
transactionAck = TransactionID / (TransactionID "-" TransactionID)

transactionRequest   = TransToken EQUAL TransactionID LBRKT actionRequest *(COMMA actionRequest) RBRKT

actionRequest        = CtxToken EQUAL ContextID LBRKT (( contextRequest [COMMA  commandRequestList]) / commandRequestList) RBRKT

contextRequest          = ((contextProperties [COMMA contextAudit]) / contextAudit)

contextProperties    = contextProperty *(COMMA contextProperty)

; at-most-once
contextProperty  = (topologyDescriptor / priority / EmergencyToken)

contextAudit    = ContextAuditToken LBRKT contextAuditProperties *(COMMA contextAuditProperties) RBRKT
; at-most-once
contextAuditProperties = ( TopologyToken / EmergencyToken / PriorityToken )
commandRequestList= ["O-"] commandRequest *(COMMA ["O-"] commandRequest)


commandRequest     = ( ammRequest / subtractRequest / auditRequest / notifyRequest / serviceChangeRequest)

transactionReply     = ReplyToken EQUAL TransactionID LBRKT [ ImmAckRequiredToken COMMA] ( errorDescriptor / actionReplyList ) RBRKT

actionReplyList      = actionReply *(COMMA actionReply )

actionReply          = CtxToken EQUAL ContextID LBRKT ( errorDescriptor / commandReply ) RBRKT

commandReply       = (( contextProperties [COMMA commandReplyList] )
                           / commandReplyList )
commandReplyList     = commandReplys *(COMMA commandReplys )

commandReplys        = (serviceChangeReply / auditReply / ammsReply / notifyReply )

;Add Move and Modify have the same request parameters
ammRequest           = (AddToken / MoveToken / ModifyToken ) EQUAL TerminationID [ LBRKT ammParameter *(COMMA ammParameter) RBRKT ]

;at-most-once
ammParameter         = (mediaDescriptor / modemDescriptor / muxDescriptor / eventsDescriptor / signalsDescriptor / digitMapDescriptor / eventBufferDescriptor / auditDescriptor)

ammsReply            = (AddToken / MoveToken / ModifyToken / SubtractToken ) EQUAL TerminationID [ LBRKT terminationAudit RBRKT ]

subtractRequest      =  ["W-"] SubtractToken EQUAL TerminationID [ LBRKT auditDescriptor RBRKT]

auditRequest         = ["W-"] (AuditValueToken / AuditCapToken ) EQUAL TerminationID LBRKT auditDescriptor RBRKT

auditReply           = (AuditValueToken / AuditCapToken ) ( contextTerminationAudit  / auditOther)

auditOther           = EQUAL TerminationID LBRKT terminationAudit RBRKT

terminationAudit     = auditReturnParameter *(COMMA auditReturnParameter)
contextTerminationAudit = EQUAL CtxToken ( terminationIDList / LBRKT errorDescriptor RBRKT )

auditReturnParameter = (mediaDescriptor / modemDescriptor / muxDescriptor / eventsDescriptor / signalsDescriptor / digitMapDescriptor / observedEventsDescriptor / eventBufferDescriptor / statisticsDescriptor / packagesDescriptor / errorDescriptor / auditItem )

auditDescriptor      = AuditToken LBRKT [ auditItem *(COMMA auditItem) ] RBRKT
notifyRequest        = NotifyToken EQUAL TerminationID LBRKT ( observedEventsDescriptor [ COMMA errorDescriptor ] ) RBRKT

notifyReply          = NotifyToken EQUAL TerminationID [ LBRKT errorDescriptor RBRKT ]

serviceChangeRequest = ServiceChangeToken EQUAL TerminationID LBRKT serviceChangeDescriptor RBRKT

serviceChangeReply   = ServiceChangeToken EQUAL TerminationID [LBRKT (errorDescriptor / serviceChangeReplyDescriptor) RBRKT]

errorDescriptor   = ErrorToken EQUAL ErrorCode LBRKT [quotedString] RBRKT

ErrorCode            = 1*4(DIGIT) ; could be extended

TransactionID        = UINT32

mId                  = (( domainAddress / domainName ) [":" portNumber]) / mtpAddress / deviceName

; ABNF allows two or more consecutive "." although it is meaningless
; in a domain name.
domainName           = "<" (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" /".") ">"
deviceName           = pathNAME

;The values 0x0, 0xFFFFFFFE and 0xFFFFFFFF are reserved.
ContextID            = (UINT32 / "*" / "-" / "$")

domainAddress        = "[" (IPv4address / IPv6address) "]"
;RFC2373 contains the definition of IP6Addresses.
IPv6address          = hexpart [ ":" IPv4address ]
IPv4address          = V4hex DOT V4hex DOT V4hex DOT V4hex
V4hex                = 1*3(DIGIT) ; "0".."225"
; this production, while occurring in RFC2373, is not referenced
; IPv6prefix           = hexpart SLASH 1*2DIGIT
hexpart          = hexseq "::" [ hexseq ] / "::" [ hexseq ] / hexseq
hexseq               = hex4 *( ":" hex4)
hex4                 = 1*4HEXDIG

portNumber           = UINT16

; An mtp address is two octets long
mtpAddress           = MTPToken LBRKT octetString RBRKT

terminationIDList    = LBRKT TerminationID *(COMMA TerminationID) RBRKT

; Total length of pathNAME must not exceed 64 chars.
pathNAME        = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" ) ["@" pathDomainName ]

; ABNF allows two or more consecutive "." although it is meaningless
; in a path domain name.
pathDomainName       = (ALPHA / DIGIT / "*" ) *63(ALPHA / DIGIT / "-" / "*" / ".")

TerminationID        = "ROOT" / pathNAME / "$" / "*"

mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT

; at-most-once per item
; and either streamParm or streamDescriptor but not both
mediaParm            = (streamParm / streamDescriptor / terminationStateDescriptor)

; at-most-once
streamParm           = ( localDescriptor / remoteDescriptor / localControlDescriptor )

streamDescriptor     = StreamToken EQUAL StreamID LBRKT streamParm *(COMMA streamParm) RBRKT

localControlDescriptor = LocalControlToken LBRKT localParm *(COMMA localParm) RBRKT

   ; at-most-once per item
localParm            = ( streamMode / propertyParm / reservedValueMode / reservedGroupMode )

reservedValueMode       = ReservedValueToken EQUAL ( "ON" / "OFF" )
reservedGroupMode       = ReservedGroupToken EQUAL ( "ON" / "OFF" )

streamMode           = ModeToken EQUAL streamModes

streamModes          = (SendonlyToken / RecvonlyToken / SendrecvToken / InactiveToken / LoopbackToken )
propertyParm         = pkgdName parmValue
parmValue            = (EQUAL alternativeValue/ INEQUAL VALUE)
alternativeValue     = ( VALUE / LSBRKT VALUE *(COMMA VALUE) RSBRKT / LBRKT VALUE *(COMMA VALUE) RBRKT / LSBRKT VALUE COLON VALUE RSBRKT )           
INEQUAL              = LWSP (">" / "<" / "#" ) LWSP
LSBRKT               = LWSP "[" LWSP
RSBRKT               = LWSP "]" LWSP

localDescriptor      = LocalToken LBRKT octetString RBRKT

remoteDescriptor     = RemoteToken LBRKT octetString RBRKT
eventBufferDescriptor = EventBufferToken LBRKT eventSpec *( COMMA eventSpec ) RBRKT
eventSpec            = pkgdName [ LBRKT eventSpecParameter *(COMMA eventSpecParameter) RBRKT ]
eventSpecParameter   = (eventStream / eventOther)

eventBufferControl     = BufferToken EQUAL ( "OFF" / LockStepToken )

terminationStateDescriptor = TerminationStateToken LBRKT terminationStateParm *( COMMA terminationStateParm ) RBRKT

; at-most-once per item
terminationStateParm =(propertyParm / serviceStates / eventBufferControl )

serviceStates        = ServiceStatesToken EQUAL ( TestToken / OutOfSvcToken / InSvcToken )

muxDescriptor        = MuxToken EQUAL MuxType  terminationIDList

MuxType              = ( H221Token / H223Token / H226Token / V76Token / extensionParameter )

StreamID             = UINT16
pkgdName             = (PackageName SLASH ItemID) / (PackageName SLASH "*") / ("*" SLASH "*")
PackageName          = NAME
ItemID               = NAME
eventsDescriptor     = EventsToken EQUAL RequestID LBRKT requestedEvent *( COMMA requestedEvent ) RBRKT

requestedEvent       = pkgdName [ LBRKT eventParameter *( COMMA eventParameter ) RBRKT ]

eventParameter       = ( embedWithSig / embedNoSig / KeepActiveToken
                           /eventDM / eventStream / eventOther )

embedWithSig         = EmbedToken LBRKT signalsDescriptor
                             [COMMA embedFirst ] RBRKT
embedNoSig           = EmbedToken LBRKT embedFirst RBRKT

; at-most-once of each
embedFirst      = EventsToken EQUAL RequestID LBRKT
               secondRequestedEvent *(COMMA secondRequestedEvent) RBRKT

secondRequestedEvent = pkgdName [ LBRKT secondEventParameter
                          *( COMMA secondEventParameter ) RBRKT ]

; at-most-once each of embedSig , KeepActiveToken, eventDM or
; eventStream
; KeepActiveToken and embedSig must not both be present
secondEventParameter = ( embedSig / KeepActiveToken / eventDM /
                            eventStream / eventOther )

embedSig  = EmbedToken LBRKT signalsDescriptor RBRKT

eventStream          = StreamToken EQUAL StreamID

eventOther           = eventParameterName parmValue

eventParameterName   = NAME

eventDM              = DigitMapToken ((EQUAL digitMapName ) /
                          (LBRKT digitMapValue RBRKT ))

signalsDescriptor    = SignalsToken LBRKT [ signalParm
                          *(COMMA signalParm)] RBRKT

signalParm           = signalList / signalRequest

signalRequest        = signalName [ LBRKT sigParameter
                          *(COMMA sigParameter) RBRKT ]
signalList           = SignalListToken EQUAL signalListId LBRKT
                          signalListParm *(COMMA signalListParm) RBRKT

signalListId         = UINT16

;exactly once signalType, at most once duration and every signal
;parameter
signalListParm       = signalRequest

signalName           = pkgdName
;at-most-once sigStream, at-most-once sigSignalType,
;at-most-once sigDuration, every signalParameterName at most once
sigParameter    = sigStream / sigSignalType / sigDuration / sigOther
                   / notifyCompletion / KeepActiveToken
sigStream            = StreamToken EQUAL StreamID
sigOther             = sigParameterName parmValue
sigParameterName     = NAME
sigSignalType        = SignalTypeToken EQUAL signalType
signalType           = (OnOffToken / TimeOutToken / BriefToken)
sigDuration          = DurationToken EQUAL UINT16
notifyCompletion     = NotifyCompletionToken EQUAL (LBRKT
                   notificationReason *(COMMA notificationReason) RBRKT )
notificationReason   = ( TimeOutToken / InterruptByEventToken
                                / InterruptByNewSignalsDescrToken
                                / OtherReasonToken )

observedEventsDescriptor = ObservedEventsToken EQUAL RequestID
                      LBRKT observedEvent *(COMMA observedEvent) RBRKT

;time per event, because it might be buffered
observedEvent        = [ TimeStamp LWSP COLON] LWSP
                          pkgdName [ LBRKT observedEventParameter
                          *(COMMA observedEventParameter) RBRKT ]

;at-most-once eventStream, every eventParameterName at most once
observedEventParameter = eventStream / eventOther

RequestID            = UINT32

modemDescriptor      = ModemToken (( EQUAL modemType) /
                          (LSBRKT modemType *(COMMA modemType) RSBRKT))
                          [ LBRKT NAME parmValue
                         *(COMMA NAME parmValue) RBRKT ]
; at-most-once
modemType            = (V32bisToken / V22bisToken / V18Token /
                           V22Token / V32Token / V34Token / V90Token /
                        V91Token / SynchISDNToken / extensionParameter)

digitMapDescriptor   = DigitMapToken EQUAL
                          ( ( LBRKT digitMapValue RBRKT ) / (digitMapName [ LBRKT digitMapValue RBRKT ]) )
digitMapName       = NAME
digitMapValue      = ["T" COLON Timer COMMA] ["S" COLON Timer COMMA] ["L" COLON Timer COMMA] digitMap
Timer              = 1*2DIGIT
digitMap = digitString / LWSP "(" LWSP digitStringList LWSP ")" LWSP
digitStringList      = digitString *( LWSP "|" LWSP digitString )
digitString          = 1*(digitStringElement)
digitStringElement   = digitPosition [DOT]
digitPosition        = digitMapLetter / digitMapRange
digitMapRange      = ("x" / LWSP "[" LWSP digitLetter LWSP "]" LWSP)
digitLetter          = *((DIGIT "-" DIGIT ) / digitMapLetter)
digitMapLetter       = DIGIT   ;Basic event symbols
                   / %x41-4B / %x61-6B ; a-k, A-K
                   / "L" / "S"   ;Inter-event timers (long, short)
                   / "Z"         ;Long duration modifier

;at-most-once, and DigitMapToken and PackagesToken are not allowed
;in AuditCapabilities command

auditItem            = ( MuxToken / ModemToken / MediaToken /
                           SignalsToken / EventBufferToken /
                           DigitMapToken / StatsToken / EventsToken /
                           ObservedEventsToken / PackagesToken )

serviceChangeDescriptor = ServicesToken LBRKT serviceChangeParm
                            *(COMMA serviceChangeParm) RBRKT

serviceChangeParm    = (serviceChangeMethod / serviceChangeReason /
                          serviceChangeDelay / serviceChangeAddress /
                         serviceChangeProfile / extension / TimeStamp /
                          serviceChangeMgcId / serviceChangeVersion )

serviceChangeReplyDescriptor = ServicesToken LBRKT
                       servChgReplyParm *(COMMA servChgReplyParm) RBRKT

;at-most-once. Version is REQUIRED on first ServiceChange response
servChgReplyParm     = (serviceChangeAddress / serviceChangeMgcId /
                          serviceChangeProfile / serviceChangeVersion )
serviceChangeMethod  = MethodToken EQUAL (FailoverToken /ForcedToken / GracefulToken / RestartToken / DisconnectedToken / HandOffToken / extensionParameter)


serviceChangeReason  = ReasonToken  EQUAL VALUE
serviceChangeDelay   = DelayToken   EQUAL UINT32
serviceChangeAddress = ServiceChangeAddressToken EQUAL VALUE
serviceChangeMgcId   = MgcIdToken   EQUAL mId
serviceChangeProfile = ProfileToken EQUAL NAME SLASH Version
serviceChangeVersion = VersionToken EQUAL Version
extension            = extensionParameter parmValue

packagesDescriptor   = PackagesToken LBRKT packagesItem
                          *(COMMA packagesItem) RBRKT

Version              = 1*2(DIGIT)
packagesItem         = NAME "-" UINT16

TimeStamp            = Date "T" Time ; per ISO 8601:1988
; Date = yyyymmdd
Date                 = 8(DIGIT)
; Time = hhmmssss
Time                 = 8(DIGIT)
statisticsDescriptor = StatsToken LBRKT statisticsParameter
                         *(COMMA statisticsParameter ) RBRKT

;at-most-once per item
statisticsParameter  = pkgdName EQUAL VALUE

topologyDescriptor   = TopologyToken LBRKT terminationA COMMA
                          terminationB COMMA topologyDirection RBRKT
terminationA         = TerminationID
terminationB         = TerminationID
topologyDirection    = BothwayToken / IsolateToken / OnewayToken

priority             = PriorityToken EQUAL UINT16

extensionParameter   = "X"  ("-" / "+") 1*6(ALPHA / DIGIT)

; octetString is used to describe SDP defined in RFC2327.
; Caution should be taken if CRLF in RFC2327 is used.
; To be safe, use EOL in this ABNF.
; Whenever "}" appears in SDP, it is escaped by "/", e.g., "/}"
octetString          = *(nonEscapeChar)
nonEscapeChar        = ( "/}" / %x01-7C / %x7E-FF )
quotedString         = DQUOTE 1*(SafeChar / RestChar/ WSP) DQUOTE

UINT16               = 1*5(DIGIT)  ; %x0-FFFF

UINT32               = 1*10(DIGIT) ; %x0-FFFFFFFF

NAME                 = ALPHA *63(ALPHA / DIGIT / "_" )
VALUE                = quotedString / 1*(SafeChar)
SafeChar             = DIGIT / ALPHA / "+" / "-" / "&" /
                          "!" / "_" / "/" / "'" / "?" / "@" /
                          "^" / "`" / "~" / "*" / "$" / "/" /
                          "(" / ")" / "%" / "|" / "."

EQUAL                = LWSP %x3D LWSP ; "="
COLON                = %x3A           ; ":"
LBRKT                = LWSP %x7B LWSP ; "{"
RBRKT                = LWSP %x7D LWSP ; "}"
COMMA                = LWSP %x2C LWSP ; ","
DOT                  = %x2E           ; "."
SLASH                = %x2F           ; "/"
ALPHA                = %x41-5A / %x61-7A ; A-Z / a-z
DIGIT                = %x30-39         ; 0-9
DQUOTE               = %x22            ; " (Double Quote)
HEXDIG               = ( DIGIT / "A" / "B" / "C" / "D" / "E" / "F" )
SP                   = %x20        ; space
HTAB                 = %x09        ; horizontal tab
CR                   = %x0D        ; Carriage return
LF                   = %x0A        ; linefeed
LWSP                 = *( WSP / COMMENT / EOL )
EOL                  = (CR [LF] / LF )
WSP                  = SP / HTAB ; white space
SEP                  = ( WSP / EOL / COMMENT) LWSP
COMMENT              = ";" *(SafeChar/ RestChar / WSP / %x22) EOL
RestChar             = ";" / "[" / "]" / "{" / "}" / ":" / "," / "#"/"<" / ">" / "="

AddToken                   = ("Add"                   / "A")
AuditToken                 = ("Audit"                 / "AT")
AuditCapToken              = ("AuditCapability"       / "AC")
AuditValueToken            = ("AuditValue"            / "AV")
AuthToken                  = ("Authentication"        / "AU")
BothwayToken               = ("Bothway"               / "BW")
BriefToken                 = ("Brief"                 / "BR")
BufferToken                = ("Buffer"                / "BF")
CtxToken                   = ("Context"               / "C")
ContextAuditToken          = ("ContextAudit"          / "CA")
DigitMapToken              = ("DigitMap"              / "DM")
DisconnectedToken          = ("Disconnected"          / "DC")
DelayToken                 = ("Delay"                 / "DL")
DurationToken              = ("Duration"              / "DR")
EmbedToken                 = ("Embed"                 / "EB")
EmergencyToken             = ("Emergency"             / "EM")
ErrorToken                 = ("Error"                 / "ER")
EventBufferToken           = ("EventBuffer"           / "EB")
EventsToken                = ("Events"                / "E")
FailoverToken              = ("Failover"              / "FL")
ForcedToken                = ("Forced"                / "FO")
GracefulToken              = ("Graceful"              / "GR")
H221Token                  = ("H221" )
H223Token                  = ("H223" )
H226Token                  = ("H226" )
HandOffToken               = ("HandOff"               / "HO")
ImmAckRequiredToken        = ("ImmAckRequired"        / "IA")
InactiveToken              = ("Inactive"              / "IN")
IsolateToken               = ("Isolate"               / "IS")
InSvcToken                 = ("InService"             / "IV")
InterruptByEventToken      = ("IntByEvent"           / "IBE")
InterruptByNewSignalsDescrToken = ("IntBySigDescr"        / "IBS")
KeepActiveToken            = ("KeepActive"            / "KA")
LocalToken                 = ("Local"                 / "L")
LocalControlToken          = ("LocalControl"          / "O")
LockStepToken              = ("LockStep"              / "SP")
LoopbackToken              = ("Loopback"              / "LB")
MediaToken                 = ("Media"                 / "M")
MegacopToken               = ("MEGACO"                / "!")
MethodToken                = ("Method"                / "MT")
MgcIdToken                 = ("MgcIdToTry"            / "MG")
ModeToken                  = ("Mode"                  / "MO")
ModifyToken                = ("Modify"                / "MF")
ModemToken                 = ("Modem"                 / "MD")
MoveToken                  = ("Move"                  / "MV")
MTPToken                   = ("MTP")
MuxToken                   = ("Mux"                   / "MX")
NotifyToken                = ("Notify"                / "N")
NotifyCompletionToken      = ("NotifyCompletion"      / "NC")
ObservedEventsToken        = ("ObservedEvents"        / "OE")
OnewayToken                = ("Oneway"                / "OW")
OnOffToken                 = ("OnOff"                 / "OO")
OtherReasonToken           = ("OtherReason"           / "OR")
OutOfSvcToken              = ("OutOfService"          / "OS")
PackagesToken              = ("Packages"              / "PG")
PendingToken               = ("Pending"               / "PN")
PriorityToken              = ("Priority"              / "PR")
ProfileToken               = ("Profile"               / "PF")
ReasonToken                = ("Reason"                / "RE")
RecvonlyToken              = ("ReceiveOnly"           / "RC")
ReplyToken                 = ("Reply"                 / "P")
RestartToken               = ("Restart"               / "RS")
RemoteToken                = ("Remote"                / "R")
ReservedGroupToken         = ("ReservedGroup"         / "RG")
ReservedValueToken         = ("ReservedValue"         / "RV")
SendonlyToken              = ("SendOnly"              / "SO")
SendrecvToken              = ("SendReceive"           / "SR")
ServicesToken              = ("Services"              / "SV")
ServiceStatesToken         = ("ServiceStates"         / "SI")
ServiceChangeToken         = ("ServiceChange"         / "SC")
ServiceChangeAddressToken  = ("ServiceChangeAddress"  / "AD")
SignalListToken            = ("SignalList"            / "SL")
SignalsToken               = ("Signals"               / "SG")
SignalTypeToken            = ("SignalType"            / "SY")
StatsToken                 = ("Statistics"            / "SA")
StreamToken                = ("Stream"                / "ST")
SubtractToken              = ("Subtract"              / "S")
SynchISDNToken             = ("SynchISDN"             / "SN")
TerminationStateToken      = ("TerminationState"      / "TS")
TestToken                  = ("Test"                  / "TE")
TimeOutToken               = ("TimeOut"               / "TO")
TopologyToken              = ("Topology"              / "TP")
TransToken                 = ("Transaction"           / "T")
ResponseAckToken           = ("TransactionResponseAck"/ "K")
V18Token                   = ("V18")
V22Token                   = ("V22")
V22bisToken                = ("V22b")
V32Token                   = ("V32")
V32bisToken                = ("V32b")
V34Token                   = ("V34")
V76Token                   = ("V76")
V90Token                   = ("V90")
V91Token                   = ("V91")
VersionToken               = ("Version"               / "V")

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值