scyther/scripts/if2spdl/parser.py

268 lines
7.9 KiB
Python
Raw Normal View History

2005-11-16 16:24:18 +00:00
#!/usr/bin/python
# requires python-pyparsing module
# http://pyparsing.sourceforge.net/
2005-11-28 14:31:16 +00:00
from pyparsing import Literal, alphas, nums, Word, oneOf, Or, Group, \
restOfLine, Forward, Optional, delimitedList
2005-11-16 19:07:19 +00:00
import Term
2005-11-16 16:24:18 +00:00
2005-11-28 14:31:16 +00:00
typedversion = False
# Generate atom parser
#
# Takes a list of tokens, returns
def atomsParser ():
global typedversion
# ------------------------------------------------------
# Atomic
# ------------------------------------------------------
# Tokens
lbr = Literal("(").suppress()
rbr = Literal(")").suppress()
comma = Literal(",").suppress()
hash = Literal("#").suppress()
equ = Literal("=").suppress()
implies = Literal("=>").suppress()
dot = Literal(".").suppress()
eol = Literal("\n").suppress()
# Basic constructors
Alfabet= alphas+nums+"_$"
Number = Word(nums)
Number.setParseAction(lambda s,l,t: [ "number", Term.TermConstant(t[0]) ])
# Typeinfo/Constant
TypeInfo = oneOf ("mr nonce pk sk fu table")
TypeInfo.setParseAction(lambda s,l,t: [ "typeinfo", Term.TermConstant(t[0]) ])
Const = Word(alphas,Alfabet)
Const.setParseAction(lambda s,l,t: [ "constant", Term.TermConstant(t[0]) ])
# Time
nTime = Group(Number)
nTime.setParseAction(lambda s,l,t: ["n", t[0] ])
xTime = Literal("xTime")
xTime.setParseAction(lambda s,l,t: ["x", 0 ])
sTime = Literal("s").suppress() + lbr + Group(Number) + rbr
sTime.setParseAction(lambda s,l,t: ["s", t[0] ])
Time = Or([nTime,xTime,sTime])
Time.setParseAction(lambda s,l,t: ["time", t[0],t[1] ])
# Two versions
Variable = Word("x",Alfabet)
Variable.setParseAction(lambda s,l,t: [ "v", Term.TermVariable(t[0],None) ])
if typedversion:
Variable = TypeInfo + "(" + Variable + ")"
# Atomic
Atomic = Or([ TypeInfo + lbr + Const + rbr, Variable])
### TEST
print Time.parseString("s(25)")
# ------------------------------------------------------
# Messages
# ------------------------------------------------------
# Base forward declaration
Message = Forward()
# Optional prime
optprime = Optional(Literal("'"))
# Agents etc
Agent = Or ([Literal("mr") + lbr + Const + rbr, Variable])
KeyTable = Or ([Literal("table") + lbr + Const + rbr, Variable])
KeyTableApp = Literal("tb") + lbr + KeyTable + comma + Agent + rbr + optprime
# Crypto
pkterm = Literal("pk") + lbr + Const + rbr + optprime
varterm = Variable + optprime
Invertible = Or( [pkterm, KeyTableApp, varterm])
PublicCypher = Literal("crypt") + lbr + Invertible + comma + Message + rbr
XOR = Literal("rcrypt") + lbr + Message + comma + Message + rbr
SymmetricCypher = Literal("scrypt") + lbr + Message + comma + Message + rbr
futerm = Or([ Literal("fu") + lbr + Const + rbr, Variable ])
Function = Literal("funct") + lbr + futerm + comma + Message + rbr
# Message composition
Concatenation = Literal("c") + lbr + Message + comma + Message + rbr
Composed = Or([ Concatenation, SymmetricCypher, XOR,
PublicCypher, Function, KeyTable, KeyTableApp ])
Message = Or ([Composed, Atomic])
# ------------------------------------------------------
# Model of honest agents
# ------------------------------------------------------
Boolean = Or ([ Literal("true"), Literal("false"), Variable ])
Session = Forward()
Session = Or ([ Literal("s") + lbr + Session + rbr, Number, Variable ])
MsgList = Forward()
MsgEtc = Literal("etc")
MsgComp = Literal("c") + lbr + Message + comma + MsgList + rbr
MsgList = Or ([ MsgEtc, Variable, MsgComp ])
Step = Or ([ Number, Variable ])
### TEST
print Message.parseString("xKb")
print MsgList.parseString("etc")
print MsgComp.parseString("c(xKb,etc)")
print MsgList.parseString("c(xA,c(xB,c(xKa,c(xKa',c(xKb,etc)))))")
# Principal fact
Principal = Literal("w") + lbr + Step + comma + Agent + comma + Agent + comma + MsgList + comma + MsgList + comma + Boolean + comma + Session + rbr
# Message fact
MessageFact = Literal("m") + lbr + Step + comma + Agent + comma + Agent + comma + Agent + comma + Message + comma + Session + rbr
# Goal fact
GoalFact = Literal ("nogniet")
GoalState = Literal ("nogniet")
# Facts and states
Fact = Or ([ Principal, MessageFact ])
State = Group(delimitedList (Fact, "."))
# Rules
mr1 = Literal("h") + lbr + Literal("s") + lbr + Literal("xTime") + rbr + rbr + dot + State
mr2 = implies
mr3 = Literal("h") + lbr + Literal("xTime") + rbr + dot + MessageFact + dot + Principal + dot + GoalFact + eol
MessageRule = mr1 + eol + mr2 + eol + mr3 + eol
InitialState = Literal("h") + lbr + Literal("xTime") + rbr + dot + State + eol
# Intruder
IntruderRule = Literal("nogniet")
# Simplification
SimplificationRule = Literal("nogniet")
# Compose all rules
Rule = Or([ InitialState, MessageRule, IntruderRule, GoalState, SimplificationRule ])
print Rule.parseFile("test.if")
def ifParse (str):
2005-11-16 16:24:18 +00:00
# Tokens
lbr = Literal("(").suppress()
rbr = Literal(")").suppress()
2005-11-28 14:31:16 +00:00
comma = Literal(",").suppress()
hash = Literal("#").suppress()
equ = Literal("=").suppress()
implies = Literal("=>").suppress()
2005-11-16 16:24:18 +00:00
# Functions to construct tuples etc
def bracket(x):
return lbr + x + rbr
def ntup(n):
x = Message
while n > 1:
2005-11-28 14:31:16 +00:00
x = x + comma + Message
2005-11-16 16:24:18 +00:00
n = n - 1
return x
def btup(n):
return bracket(ntup(n))
def funcy(x,y):
return x + bracket(y)
def ftup(x,n):
return funcy(x, ntup(n))
# Message section
Alfabet= alphas+nums+"_$"
2005-11-16 19:07:19 +00:00
Variable = Word("x",Alfabet).setParseAction(lambda s,l,t: [ Term.TermVariable(t[0],None) ])
Constant = Word(alphas,Alfabet).setParseAction(lambda s,l,t: [ Term.TermConstant(t[0]) ])
Number = Word(nums).setParseAction(lambda s,l,t: [ Term.TermConstant(t[0]) ])
2005-11-16 16:24:18 +00:00
Basic = MatchFirst([ Variable, Constant, Number ])
2005-11-16 19:50:40 +00:00
# Message definition is recursive
2005-11-16 16:24:18 +00:00
Message = Forward()
def parseType(s,l,t):
2005-11-16 19:50:40 +00:00
if t[0][0] == "pk":
# Public key thing, that's not really a type for
# us but a function
return [Term.TermEncrypt(t[0][1], t[0][0]) ]
term = t[0][1]
term.setType(t[0][0])
return [term]
2005-11-16 19:07:19 +00:00
TypeInfo = oneOf ("mr nonce pk sk fu table").setParseAction(lambda s,l,t: [ Term.TermConstant(t[0]) ])
TypeMsg = Group(TypeInfo + lbr + Message + rbr).setParseAction(parseType)
def parseCrypt(s,l,t):
# Crypto types are ignored for now
2005-11-16 19:50:40 +00:00
type = t[0][0]
if type == "c":
return [Term.TermTuple( t[0][1],t[0][2] ) ]
return [Term.TermEncrypt(t[0][2],t[0][1])]
2005-11-16 19:07:19 +00:00
2005-11-16 16:24:18 +00:00
CryptOp = oneOf ("crypt scrypt c funct rcrypt tb")
2005-11-28 14:31:16 +00:00
CryptMsg = Group(CryptOp + lbr + Message + comma + Message + rbr).setParseAction(parseCrypt)
def parseSMsg(s,l,t):
return [Term.TermEncrypt(t[0][1],Term.Termconstant("succ") )]
SMsg = Group(Literal("s") + lbr + Message + rbr)
def parsePrime(s,l,t):
# for now, we simply ignore the prime (')
return [t[0][0]]
Message << Group(Or ([TypeMsg, CryptMsg, SMsg, Basic]) + Optional(Literal("'"))).setParseAction(parsePrime)
2005-11-16 16:24:18 +00:00
# Fact section
Request = Group("request" + btup(4))
Witness = Group("witness" + btup(4))
2005-11-28 14:31:16 +00:00
Give = Group("give" + lbr + Message + comma + ftup(Literal("f"),
1) + rbr)
2005-11-28 14:31:16 +00:00
Secret = Group("secret" + lbr + Message + comma +
ftup(Literal("f"),1) + rbr)
TimeFact = Group(ftup (Literal("h"), 1))
IntruderKnowledge = Group(ftup (Literal("i"), 1))
MessageFact = Group(ftup(Literal("m"),6))
Principal = Group(ftup(Literal("w"), 7))
2005-11-16 16:24:18 +00:00
Fact = Principal | MessageFact | IntruderKnowledge | TimeFact | Secret | Give | Witness | Request
#State = Fact + OptioZeroOrMore ("." + Fact)
2005-11-16 18:19:50 +00:00
State = Group(delimitedList (Fact, "."))
2005-11-16 16:24:18 +00:00
# Rules and labels
rulename = Word (alphanums + "_")
rulecategory = oneOf("Protocol_Rules Invariant_Rules Decomposition_Rules Intruder_Rules Init Goal")
2005-11-28 14:31:16 +00:00
label = hash + "lb" + equ + rulename + comma + "type" + equ + rulecategory
2005-11-16 18:19:50 +00:00
rule = Group(State + Optional(implies + State))
2005-11-16 16:24:18 +00:00
labeledrule = Group(label + rule)
typeflag = hash + "option" + equ + oneOf ("untyped","typed")
2005-11-16 16:24:18 +00:00
# A complete file
2005-11-16 18:19:50 +00:00
iffile = typeflag + Group(OneOrMore(labeledrule))
2005-11-16 16:24:18 +00:00
parser = iffile
parser.ignore("##" + restOfLine)
return parser.parseString(str)
2005-11-28 14:31:16 +00:00
def main():
global typedversion
typedversion = False
atomsParser()
if __name__ == '__main__':
main()
2005-11-16 16:24:18 +00:00