pykiss

Python Kisekae set viewer
git clone https://code.literati.org/pykiss.git
Log | Files | Refs | LICENSE

kissparser.py (6064B)


      1 # Copyright (C) 2003 Sean R. Lynch <seanl@chaosring.org>
      2 #
      3 # This program is free software; you can redistribute it and/or modify
      4 # it under the terms of the GNU General Public License as published by
      5 # the Free Software Foundation; either version 2 of the License, or
      6 # (at your option) any later version.
      7 #
      8 # This program is distributed in the hope that it will be useful,
      9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11 # GNU General Public License for more details.
     12 #
     13 # You should have received a copy of the GNU General Public License
     14 # along with this program; if not, write to the Free Software
     15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     16 
     17 import re, sys
     18 
     19 class ParseError(Exception): pass
     20 
     21 class KissParser:
     22     def __init__(self, handler=None):
     23 	self.fkiss_started = 0
     24 	self.event = None
     25         self.actions = []
     26 	self.setindex = -1
     27         self.handler = handler
     28         
     29     def parse_args(self, line):
     30 	# Line should already be stripped and only have the stuff in parentheses
     31 	args = []
     32 	while line:
     33 	    m = re.match("#([0-9]+)\s*[,\.]?\s*(.*)", line)
     34 	    if m:
     35                 objnum = int(m.group(1))
     36                 obj = self.handler.get_obj(objnum)
     37                 if obj is None:
     38                     self.handler.warn("Object #%d not found." % objnum)
     39                     return None
     40                 args.append(obj)
     41 		line = m.group(2)
     42 		continue
     43 	    
     44 	    m = re.match("(-?[0-9]+)\s*[,\.]?\s*(.*)", line)
     45 	    if m:
     46 		args.append(int(m.group(1)))
     47 		line = m.group(2)
     48 		continue
     49 	    
     50 	    m = re.match('"([^"]*)"?\s*[,\.]?\s*(.*)', line)
     51 	    if m:
     52 		args.append(m.group(1))
     53 		line = m.group(2)
     54 		continue
     55 	    
     56 	    raise ParseError, line
     57 	    
     58 	return tuple(args)
     59 
     60     def parse_fkiss(self, line):
     61         line = line.strip()
     62         while line:
     63             m = re.match('(\w+)\s*(?:\(([^)]*)\))?', line)
     64             if not m: return
     65             self.parse_command(m.group(1), m.group(2))
     66             line = line[m.end():].lstrip()
     67         
     68 
     69     def parse_command(self, name, argstr):
     70 	if name == 'EventHandler': 
     71 	    if self.fkiss_started:
     72 		raise ParseError, 'EventHandler called more than once!'
     73 	    self.fkiss_started = 1
     74             return
     75 	elif not self.fkiss_started: return
     76 
     77 
     78         name = name.lower()
     79 	args = self.parse_args(argstr)
     80         if args is None: return
     81 
     82         if self.handler.is_action(name):
     83             # Adding another action
     84             if args is not None:
     85                 if self.event is None:
     86                     self.handler.warn("Attempted to add action without an event: %s%r" %
     87                               (name, args))
     88                 else:
     89                     # Add an action to the current event
     90                     self.actions.append((name, args))
     91             
     92         else:
     93             # Starting a new event
     94             if self.event is not None:
     95                 # Store the last event
     96                 if self.actions:
     97                     self.handler.add_event(self.event[0], self.event[1],
     98                                            self.actions)
     99                 else:
    100                     self.handler.warn("Attempted to add an empty event: %s%r" %
    101                               self.event)
    102 
    103             # Set up the new event
    104             self.event = name, args
    105             self.actions = []  
    106             
    107     def parse_field(self, width, height):
    108         self.handler.set_size((int(width), int(height)))
    109 	
    110     def parse_palette(self, palfile):
    111         palfile = palfile.lower()
    112         self.handler.add_palette(palfile)
    113 	
    114     def parse_border(self, bordercol):
    115 	self.handler.set_border = int(bordercol)
    116 	
    117     def parse_cel(self, objnum, fixval, name, paloffset, groups, trans):
    118         name = name.lower()
    119         
    120 	if fixval is None: fixval = 0
    121 	else: fixval = int(fixval)
    122     
    123 	if paloffset is None: paloffset = 0
    124 	else: paloffset = int(paloffset)
    125 	
    126 	if groups is not None: 
    127 	    groups = [int(group) for group in groups.split()]
    128 	
    129 	if trans is None: trans = 0
    130 	else: trans = int(trans)
    131 	
    132 	self.handler.add_cel(name, int(objnum), fixval, paloffset, groups, trans)
    133         
    134     def parse_set(self, palnum, positions):
    135 	self.setindex += 1
    136         self.handler.set_palette(self.setindex, int(palnum))
    137 	self.objindex = 0
    138 	self.parse_setcont(positions)
    139     
    140     def parse_setcont(self, positions):
    141 	for pos in positions.split():
    142             if pos == '*': pos = (0, 0)
    143             else:
    144                 try: pos = tuple([int(x) for x in pos.split(',', 1)])
    145                 except ValueError:
    146                     self.handler.warn("Trailing garbage in set layout: %r" % pos)
    147                     return 
    148             if len(pos) != 2: pos = (pos[0], 0)
    149 
    150             self.handler.set_objpos(self.objindex, self.setindex, pos)
    151 
    152 	    self.objindex += 1
    153 	
    154 	
    155     regexps = [("\s*;?\s*@(.+)", parse_fkiss),
    156 	       ("\(\s*([0-9]+)\s*,\s*([0-9]+)\s*\)", parse_field),
    157 	       ("%(\S+)", parse_palette),
    158 	       ("\[(\d+)", parse_border),
    159 	       ("#([0-9]+)(?:\.([0-9]+))?\s+(\S+)(?:\s+\*(\d+))?(?:\s+:([\d\s]+))?(?:\s*;%t(\d+))?", parse_cel),
    160 	       ("\$([0-9]+)\s+([^;]+)", parse_set),
    161 	       ("\s+([^;]+)", parse_setcont)]
    162     
    163     def parse(self, cnf):
    164 	f = open(cnf)
    165         for line in f.xreadlines():
    166             line = line.rstrip()
    167             # Skip comments and blank lines
    168             if not line: continue
    169             
    170             for r, func in self.regexps:
    171                 m = re.match(r, line)
    172                 if m:
    173                     rest = line[m.end():].strip()
    174                     if rest and rest[0] != ';':
    175                         self.handler.warn('Trailing garbage: %r' % rest)
    176 		    
    177                     apply(func, (self,) + m.groups())
    178                     break
    179             else:
    180                 if line[0] != ';': 
    181                     self.handler.warn("Homy don't parse that: %r" % line)
    182 
    183         # Make sure to pass the last event to the handler
    184         if self.event:
    185             self.handler.add_event(self.event[0], self.event[1], self.actions)
    186 
    187 
    188