-
Notifications
You must be signed in to change notification settings - Fork 4
/
EssexParser.py
executable file
·90 lines (81 loc) · 3.16 KB
/
EssexParser.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#=========================================================================
# This is OPEN SOURCE SOFTWARE governed by the Gnu General Public
# License (GPL) version 3, as described at www.opensource.org.
# Copyright (C)2016 William H. Majoros ([email protected]).
#=========================================================================
from __future__ import (absolute_import, division, print_function,
unicode_literals, generators, nested_scopes, with_statement)
from builtins import (bytes, dict, int, list, object, range, str, ascii,
chr, hex, input, next, oct, open, pow, round, super, filter, map, zip)
import os
from EssexNode import EssexNode
from EssexScanner import EssexScanner
from EssexToken import EssexToken
######################################################################
#
# A parser for the Essex language, which is a simple alternative to XML
# and looks like LISP programs ("S-Expressions" -- hence the name "Essex").
# It generates tree data structures built out of EssexNode objects.
#
# Attributes:
# file : file handle
# isOpen : boolean
# scanner : EssexScanner
# Methods:
# parser=EssexParser(filename) # filename is optional
# parser.open(filename) # unnecessary if you gave filename to ctor
# parser.close()
# tree=parser.nextElem() # returns root of the tree
# forest=parser.parseAll() # returns an array of trees
# Class methods:
# forest=EssexParser.loadFile(filename) # returns array of trees
######################################################################
class EssexParser:
def __init__(self,filename=None):
self.isOpen=False
if(filename): self.open(filename)
def open(self,filename):
if(self.isOpen): self.close()
if(not os.path.exists(filename)):
raise Exception(filename+" does not exist")
file=self.file=open(filename,"r")
self.isOpen=True
self.scanner=EssexScanner(file)
def close(self):
if(self.isOpen):
self.file.close()
self.isOpen=False
self.scanner=None
def parseAll(self):
forest=[]
while(True):
tree=self.nextElem()
if(not tree): break
forest.append(tree)
return forest
@classmethod
def loadFile(cls,filename):
parser=EssexParser(filename)
return parser.parseAll()
def nextElem(self):
if(not self.isOpen): raise Exception("file is not open")
scanner=self.scanner
token=scanner.nextToken()
if(not token): return None
if(token.isOpenParen()): return self.parseTuple()
elif(token.isLiteral()): return token.getLexeme()
else:
lexeme=token.getLexeme()
exit("Syntax error near \n"+token+"\n")
def parseTuple(self):
"""PRECONDITION: a "(" has already been matched"""
elements=[]
scanner=self.scanner
while(True):
token=scanner.nextToken()
if(not token): break
if(token.isOpenParen()):
elements.append(self.parseTuple())
elif(token.isCloseParen()): break
else: elements.append(token.getLexeme())
return EssexNode(elements)