'''Parser dan compiler file isi halaman untuk situs AdhiHargo.net.
Sangat sederhana, dikodekan kurang dari satu jam.
Author : Adhi Hargo
Last modified : 21/04/2006 0:08:41
'''
__all__ = [ 'Parser',
'ParserError',
'Compiler',
'CompilerError' ]
# Bila sedang dalam definisi sebuah label, semua karakter whitespace di bawah akan
# diganti dengan karakter spasi biasa.
WSPACE = [' ','\w','\r','\f','\v','\t']
# Pasangan LABEL--DEFINISI_LABEL harus berada dalam baris terpisah, namun karena
# baris kosong boleh berada dalam definisi label, harus ada penanda khusus.
# Penanda tersebut harus berada di satu baris tersendiri, dan hanya berisi satu
# karakter non-whitespace, yaitu...
DEFINITION_END = '%'
# Karakter ini memisahkan antara label dan definisi label.
MAK_COMBLANG = '='
# ==============================================================================
# Parser File Isi
# ==============================================================================
class Parser:
def __init__(self):
self.reset()
def reset(self):
self.tree = {}
self.__in_def__ = False
self.__current_label__ = []
self.__current_def__ = []
self.__current_line__ = ''
self.__current_cidx__ = 0 # Indeks karakter yang terakhir diolah
def feed(self,object):
'''Memasukkan string input, secara implisit mengaktifkan parser.
Argumen harus berupa string input atau struktur data iterable yang
memuat string input tersebut. Hasil parse dapat diambil dalam atribut
"tree" milik objek parser yang bersangkutan, bila proses parsing
berjalan dengan baik.'''
if type(object) is type(''):
self.__parse_line__(object)
elif hasattr(object,'__iter__'):
for line in object:
self.__parse_line__(line)
else:
raise TypeError, 'Objek yang dimasukkan harus string atau iterable.'
def __parse_line__(self, line):
self.__current_line__ = line
self.__current_cidx__ = 0
if line.strip() == DEFINITION_END:
if self.__in_def__:
label_name = ''.join(self.__current_label__).strip()
label_def = ''.join(self.__current_def__)
self.tree[label_name] = label_def
self.__current_label__ = []
self.__current_def__ = []
self.__in_def__ = False
elif self.__in_def__:
self.__handle_def__()
else:
self.__handle_label__()
def __handle_label__(self):
line = self.__current_line__
for i in range(self.__current_cidx__, len(line)):
c = line[i]
if c is MAK_COMBLANG:
self.__current_cidx__ = i + 1
self.__in_def__ = True
break
else:
self.__current_label__.append(c)
self.__handle_def__()
def __handle_def__(self):
line = self.__current_line__
for c in line[self.__current_cidx__:]:
if c in WSPACE:
self.__current_def__.append(' ')
else: self.__current_def__.append(c)
# ==============================================================================
# Kompiler File Isi
# ==============================================================================
class Compiler:
def __init__(self):
self.reset()
def reset(self):
self.string = ''
self.strings = []
def feed(self,object):
'''Memasukkan struktur input, secara implisit mengaktifkan kompiler.
Argumen harus berupa struktur data dictionary. Iterator untuk string
keluaran diambil dari atribut "strings" dari objek kompiler yang
bersangkutan.
'''
if not type(object) is type({}):
raise CompilerError, 'Objek yang dimasukkan harus bertipe dictionary.'
for label in object.keys():
label_def = str(object[label])
def_str = "%s %s %s\n%s\n" % (label, MAK_COMBLANG, label_def, DEFINITION_END)
self.strings.append(def_str)
# ==============================================================================
class ParserError(StandardError):
pass
class CompilerError(StandardError):
pass
# ==============================================================================
if __name__ == '__main__':
dummy = '''
Adhi Hargo = asdmkv;c adsdsa;lk das
dsajk;sd lasd ;lksa d
%
Gentur Prabowo = Nih, boleh ada spasi di atas label.
dsaodsapo
dsapodksaodksa
%
Marimutu = Halo, nama saya Marimutu. Perut saya gendut.
Namun bagaimanapun saya hanya pengusaha, bukan koruptor. Yang bisa korupsi kan
cuma pejabat?
%Ooooo. Kalau ada string non-whitespace di belakang separator, tetap ikut!
%
'''.split('\n')
parser = Parser()
parser.feed(dummy)
compiler = Compiler()
compiler.feed(parser.tree)
print "Pohon hasil parsing = \n%s\n" % parser.tree
print "String hasil kompilasi pohon parse = \n%s\n" % ''.join(compiler.strings)