Home | History | Annotate | Download | only in bindings
      1 # Capstone Disassembler Engine
      2 # By Dang Hoang Vu, 2013
      3 from __future__ import print_function
      4 import sys, re
      5 
      6 INCL_DIR = '../include/'
      7 
      8 include = [ 'arm.h', 'arm64.h', 'mips.h', 'x86.h', 'ppc.h', 'sparc.h', 'systemz.h', 'xcore.h' ]
      9 
     10 template = {
     11     'java': {
     12             'header': "// For Capstone Engine. AUTO-GENERATED FILE, DO NOT EDIT\npackage capstone;\n\npublic class %s_const {\n",
     13             'footer': "}",
     14             'line_format': '\tpublic static final int %s = %s;\n',
     15             'out_file': './java/capstone/%s_const.java',
     16             # prefixes for constant filenames of all archs - case sensitive
     17             'arm.h': 'Arm',
     18             'arm64.h': 'Arm64',
     19             'mips.h': 'Mips',
     20             'x86.h': 'X86',
     21             'ppc.h': 'Ppc',
     22             'sparc.h': 'Sparc',
     23             'systemz.h': 'Sysz',
     24             'xcore.h': 'Xcore',
     25             'comment_open': '\t//',
     26             'comment_close': '',
     27         },
     28     'python': {
     29             'header': "# For Capstone Engine. AUTO-GENERATED FILE, DO NOT EDIT [%s_const.py]\n",
     30             'footer': "",
     31             'line_format': '%s = %s\n',
     32             'out_file': './python/capstone/%s_const.py',
     33             # prefixes for constant filenames of all archs - case sensitive
     34             'arm.h': 'arm',
     35             'arm64.h': 'arm64',
     36             'mips.h': 'mips',
     37             'x86.h': 'x86',
     38             'ppc.h': 'ppc',
     39             'sparc.h': 'sparc',
     40             'systemz.h': 'sysz',
     41             'xcore.h': 'xcore',
     42             'comment_open': '#',
     43             'comment_close': '',
     44         },
     45     'ocaml': {
     46             'header': "(* For Capstone Engine. AUTO-GENERATED FILE, DO NOT EDIT [%s_const.ml] *)\n",
     47             'footer': "",
     48             'line_format': 'let _%s = %s;;\n',
     49             'out_file': './ocaml/%s_const.ml',
     50             # prefixes for constant filenames of all archs - case sensitive
     51             'arm.h': 'arm',
     52             'arm64.h': 'arm64',
     53             'mips.h': 'mips',
     54             'x86.h': 'x86',
     55             'ppc.h': 'ppc',
     56             'sparc.h': 'sparc',
     57             'systemz.h': 'sysz',
     58             'xcore.h': 'xcore',
     59             'comment_open': '(*',
     60             'comment_close': ' *)',
     61         },
     62 }
     63 
     64 # markup for comments to be added to autogen files
     65 MARKUP = '//>'
     66 
     67 def gen(lang):
     68     global include, INCL_DIR
     69     print('Generating bindings for', lang)
     70     templ = template[lang]
     71     for target in include:
     72         prefix = templ[target]
     73         outfile = open(templ['out_file'] %(prefix), 'wb')   # open as binary prevents windows newlines
     74         outfile.write((templ['header'] % (prefix)).encode("utf-8"))
     75 
     76         lines = open(INCL_DIR + target).readlines()
     77 
     78         count = 0
     79         for line in lines:
     80             line = line.strip()
     81 
     82             if line.startswith(MARKUP):  # markup for comments
     83                 outfile.write(("\n%s%s%s\n" %(templ['comment_open'], \
     84                                               line.replace(MARKUP, ''), \
     85                                               templ['comment_close']) ).encode("utf-8"))
     86                 continue
     87 
     88             if line == '' or line.startswith('//'):
     89                 continue
     90 
     91             if not line.startswith(prefix.upper()):
     92                 continue
     93 
     94             tmp = line.strip().split(',')
     95             for t in tmp:
     96                 t = t.strip()
     97                 if not t or t.startswith('//'): continue
     98                 f = re.split('\s+', t)
     99 
    100                 if f[0].startswith(prefix.upper()):
    101                     if len(f) > 1 and f[1] not in '//=':
    102                         print("Error: Unable to convert %s" % f)
    103                         continue
    104                     elif len(f) > 1 and f[1] == '=':
    105                         rhs = ''.join(f[2:])
    106                     else:
    107                         rhs = str(count)
    108                         count += 1
    109 
    110                     try:
    111                         count = int(rhs) + 1
    112                         if (count == 1):
    113                             outfile.write(("\n").encode("utf-8"))
    114                     except ValueError:
    115                         if lang == 'ocaml':
    116                             # ocaml uses lsl for '<<', lor for '|'
    117                             rhs = rhs.replace('<<', ' lsl ')
    118                             rhs = rhs.replace('|', ' lor ')
    119                             # ocaml variable has _ as prefix
    120                             if rhs[0].isalpha():
    121                                 rhs = '_' + rhs
    122 
    123                     outfile.write((templ['line_format'] %(f[0].strip(), rhs)).encode("utf-8"))
    124 
    125         outfile.write((templ['footer']).encode("utf-8"))
    126         outfile.close()
    127 
    128 def main():
    129     try:
    130         gen(sys.argv[1])
    131     except:
    132         raise RuntimeError("Unsupported binding %s" % sys.argv[1])
    133 
    134 if __name__ == "__main__":
    135     if len(sys.argv) < 2:
    136         print("Usage:", sys.argv[0], " <bindings: java|python|ocaml>")
    137         sys.exit(1)
    138     main()
    139