From eb00aa8362ba0faa1e885f636e94675d7ed46f0e Mon Sep 17 00:00:00 2001 From: Muhammad Shahbaz Date: Tue, 7 Jul 2015 22:09:25 -0700 Subject: [PATCH 1/6] initial commits for netasm_dsl front_end --- netasm/front_ends/__init__.py | 1 + .../netasm_dsl/__init__.py} | 0 netasm/front_ends/netasm_dsl/dump | 2 + netasm/front_ends/netasm_dsl/dumper.py | 30 ++ netasm/front_ends/netasm_dsl/lexer.py | 144 +++++ netasm/front_ends/netasm_dsl/netasm_dsl.bnf | 102 ++++ netasm/front_ends/netasm_dsl/parser.py | 507 ++++++++++++++++++ netasm/front_ends/netasm_dsl/test.netasm | 48 ++ netasm/netasm/core/syntax.py | 2 +- netasm/netasm/parse.py | 36 -- 10 files changed, 835 insertions(+), 37 deletions(-) create mode 100644 netasm/front_ends/__init__.py rename netasm/{netasm/core/parse.py => front_ends/netasm_dsl/__init__.py} (100%) create mode 100644 netasm/front_ends/netasm_dsl/dump create mode 100644 netasm/front_ends/netasm_dsl/dumper.py create mode 100644 netasm/front_ends/netasm_dsl/lexer.py create mode 100644 netasm/front_ends/netasm_dsl/netasm_dsl.bnf create mode 100644 netasm/front_ends/netasm_dsl/parser.py create mode 100644 netasm/front_ends/netasm_dsl/test.netasm delete mode 100644 netasm/netasm/parse.py diff --git a/netasm/front_ends/__init__.py b/netasm/front_ends/__init__.py new file mode 100644 index 0000000..e317e67 --- /dev/null +++ b/netasm/front_ends/__init__.py @@ -0,0 +1 @@ +__author__ = 'shahbaz' diff --git a/netasm/netasm/core/parse.py b/netasm/front_ends/netasm_dsl/__init__.py similarity index 100% rename from netasm/netasm/core/parse.py rename to netasm/front_ends/netasm_dsl/__init__.py diff --git a/netasm/front_ends/netasm_dsl/dump b/netasm/front_ends/netasm_dsl/dump new file mode 100644 index 0000000..06d442e --- /dev/null +++ b/netasm/front_ends/netasm_dsl/dump @@ -0,0 +1,2 @@ +Policy(Decls(TableDecls(TableDecls()),InstructionCollection.Code(Fields('outport','inport','bit_length'),InstructionCollection.Instructions(InstructionCollection.ADD(OperandCollection.Field(Field('eth_dst')),Size(48)),InstructionCollection.ADD(OperandCollection.Field(Field('eth_src')),Size(48)),InstructionCollection.ADD(OperandCollection.Field(Field('eth_type')),Size(16)),InstructionCollection.LD(OperandCollection.Field(Field('eth_dst')),OperandCollection.Value(Value(0,Size(16)))),InstructionCollection.LD(OperandCollection.Field(Field('eth_src')),OperandCollection.Value(Value(48,Size(16)))),InstructionCollection.LD(OperandCollection.Field(Field('eth_type')),OperandCollection.Value(Value(96,Size(16)))),InstructionCollection.BR(OperandCollection.Field(Field('eth_type')),OperatorCollection.Eq,OperandCollection.Value(Value(2048,Size(16))),Label('"LBL_PARSE_0"')),InstructionCollection.DRP(Reason('"PARSER"','"UNHANDLED_IP_PAYLOAD"')),InstructionCollection.CNC(InstructionCollection.Codes(InstructionCollection.Code(Fields(''),InstructionCollection.Instructions(InstructionCollection.LD(OperandCollection.Field(Field('eth_type')),OperandCollection.Value(Value(96,Size(64)))),InstructionCollection.HLT())),InstructionCollection.Code(Fields(''),InstructionCollection.Instructions(InstructionCollection.HLT())))),InstructionCollection.HLT()))) +Total errors: 0 \ No newline at end of file diff --git a/netasm/front_ends/netasm_dsl/dumper.py b/netasm/front_ends/netasm_dsl/dumper.py new file mode 100644 index 0000000..941b494 --- /dev/null +++ b/netasm/front_ends/netasm_dsl/dumper.py @@ -0,0 +1,30 @@ +__author__ = 'shahbaz' + +from optparse import OptionParser +from parser import Parser + + +def main(): + op = OptionParser() + op.add_option('--ifile', action="store", dest="ifile") + op.add_option('--ofile', action="store", dest="ofile") + + op.set_defaults(ofile='./dump') + options, args = op.parse_args() + + if not options.ifile: + print '--ifile flag not specified.' + exit(1) + + ifile = open(options.ifile) + ofile = open(options.ofile, 'w') + + parser = Parser() + policy, errors_cnt = parser.parse(ifile.read()) + + ofile.write(str(policy)) + ofile.write('\n') + ofile.write('Total errors: ' + str(errors_cnt)) + + +main() diff --git a/netasm/front_ends/netasm_dsl/lexer.py b/netasm/front_ends/netasm_dsl/lexer.py new file mode 100644 index 0000000..7d32526 --- /dev/null +++ b/netasm/front_ends/netasm_dsl/lexer.py @@ -0,0 +1,144 @@ +__author__ = 'shahbaz' + +from ply import lex +from ply.lex import TOKEN + + +class Lexer: + def __init__(self): + self.lexer = None + + keywords = ( + # Operators + 'Add', 'Sub', 'Mul', 'Div', 'And', 'Or', 'Xor', + + # Comparators + 'Eq', 'Neq', 'Lt', 'Gt', 'Le', 'Ge', + + # Instructions + 'ID', 'DRP', 'CTR', 'ADD', 'RMV', + 'LD', 'ST', 'OP', 'PUSH', 'POP', + 'BR', 'JMP', 'LBL', 'LDt', 'STt', + 'INCt', 'LKt', 'CRC', 'HSH', 'HLT', + 'CNC', 'ATM', 'SEQ', + + # Match types + 'Binary', 'Ternary', + + # Table types + 'CAM', 'RAM', 'HASH', + ) + + keywords_map = {} + for keyword in keywords: + keywords_map[keyword] = keyword + + tokens = ( + # Identifiers and strings + 'IDN', 'STR', + + # Numbers and base + 'NUM', 'BASE', + + # Delimeters + 'LPAREN', 'RPAREN', # () + 'LBRACKET', 'RBRACKET', # [] + + # Assignment, (semi) colon, and coma + 'EQUAL', 'COLON', 'SEMI', 'COMMA', + + # Special + 'S_DECLS', 'S_CODE', 'S_FIELDS', 'S_INSTRS' + ) + + tokens += keywords + + t_ignore = ' \t' + + t_LPAREN = r'\(' + t_RPAREN = r'\)' + t_LBRACKET = r'\[' + t_RBRACKET = r'\]' + + t_EQUAL = r'=' + t_COLON = r':' + t_SEMI = r';' + t_COMMA = r',' + + t_S_DECLS = r'\.decls' + t_S_CODE = r'\.code' + t_S_FIELDS = r'\.fields' + t_S_INSTRS = r'\.instrs' + + number = r'[0-9]+' + + @TOKEN(number) + def t_NUM(self, t): + # t.value = int(t.value) + return t + + t_BASE = r"'[bBoOdDhH]" + + identifier = r'[a-zA-Z_][0-9a-zA-Z_]*' + + @TOKEN(identifier) + def t_IDN(self, t): + t.type = self.keywords_map.get(t.value, "IDN") + return t + + t_STR = '\"[^\"]*\"' + + comment = r'[#][^\n]*' + + @TOKEN(comment) + def t_comment(self, t): + pass + + newline = r'\n+' + + @TOKEN(newline) + def t_newline(self, t): + t.lexer.lineno += len(t.value) + + def t_error(self, t): + print "Illegal character '%s'" % t.value[0] + t.lexer.skip(1) + + def warning(self, t): + print "Illegal character '%s'" % t.value[0] + t.lexer.skip(1) + + def reset_lineno(self): + self.lexer.lineno = 1 + + def get_lineno(self): + return self.lexer.lineno + + def input(self, text): + self.lexer.input(text) + + def token(self): + t = self.lexer.token() + return t + + def find_tok_column(self, token): + last_cr = self.lexer.lexdata.rfind('\n', 0, token.lexpos) + return token.lexpos - last_cr + + def build(self, **kwargs): + self.lexer = lex.lex(module=self, **kwargs) + + +if __name__ == '__main__': + lexer = Lexer() + lexer.build() + lexer.input(''' +.code + .instructions + HLT + ''') + + while True: + t = lexer.token() + if not t: break + print t diff --git a/netasm/front_ends/netasm_dsl/netasm_dsl.bnf b/netasm/front_ends/netasm_dsl/netasm_dsl.bnf new file mode 100644 index 0000000..6ccc072 --- /dev/null +++ b/netasm/front_ends/netasm_dsl/netasm_dsl.bnf @@ -0,0 +1,102 @@ + +(* NetASM Domain-Specific Language *) + + ::= [0-9]+ + + ::= [a-zA-Z_][0-9a-zA-Z_]* + + = '[^']*' + + ::= 'b | 'B | 'o | 'O | 'd | 'D | 'h | 'H + + ::= ? ? + + ::= + + ::= + + ::= ? {"," } + + ::= + +