-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlexer_parser.py
More file actions
154 lines (123 loc) · 3.88 KB
/
lexer_parser.py
File metadata and controls
154 lines (123 loc) · 3.88 KB
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
from sly import Lexer, Parser
from nodes import TYPE_DICT, Block, Content, Line
from utils import fix_string, rgb_to_hex
EXCEPT = False
class BlockLexer(Lexer):
tokens = { BLOCK, LINE, NAME, NUMBER, COLOR, TEXT, FRAME, TYPE_NAME, CONNECT, STRING, TYPE }
ignore = ' \t'
literals = { '{','}','>','<',',',':','(',')' }
# Tokens
TYPE = r'\b(operation|condition|input/output|start/stop)\b'
BLOCK = r'block'
LINE = r'line'
COLOR = r'color'
TEXT = r'text'
FRAME = r'frame'
TYPE_NAME = r'type'
CONNECT = r'connect'
NAME = r'[a-zA-Z_][a-zA-Z0-9_]*'
STRING = r'".+"'
@_(r'\d+')
def NUMBER(self, t):
t.value = int(t.value)
return t
@_(r'\n+')
def newline(self, t):
self.lineno += t.value.count('\n')
def error(self, t):
print(f"Illegal character {t.value[0]} in line {self.lineno}")
self.index += 1
class BlockParser(Parser):
tokens = BlockLexer.tokens
@_('file')
def input(self, p):
return p.file
@_('lines')
def file(self, p):
return [p.lines]
@_('lines file')
def file(self, p):
(p.file).append(p.lines)
return p.file
@_('BLOCK NAME "{" block_content "}"')
def lines(self, p):
return Block(p.NAME, p.block_content)
@_('LINE NAME "{" line_content "}"')
def lines(self, p):
return Line(p.NAME, p.line_content)
@_('block_line')
def block_content(self, p):
return Content().add(*p.block_line)
@_('block_line block_content')
def block_content(self, p):
return (p.block_content).add(*p.block_line)
@_('COLOR ":" "(" tuple ")"')
def block_line(self, p):
return ("fillcolor", p.tuple)
@_('TYPE_NAME ":" TYPE')
def block_line(self, p):
return ("shape",TYPE_DICT[p.TYPE])
@_('TEXT ":" STRING')
def block_line(self, p):
return ("label", fix_string(p.STRING))
@_('FRAME ":" "(" tuple ")"')
def block_line(self, p):
return ("color",p.tuple)
@_('NUMBER "," NUMBER "," NUMBER')
def tuple(self, p):
return f"{rgb_to_hex((p.NUMBER0,p.NUMBER1,p.NUMBER2))}"
@_('line_line')
def line_content(self, p):
return Content().add(*p.line_line)
@_('line_line line_content')
def line_content(self, p):
return (p.line_content).add(*p.line_line)
@_('COLOR ":" "(" tuple ")"')
def line_line(self, p):
return ("color", p.tuple)
@_('TEXT ":" STRING')
def line_line(self, p):
return ("label", fix_string(p.STRING))
@_('CONNECT ":" connect_nt')
def line_line(self, p):
return ("edge", p.connect_nt)
@_('any ">" NAME')
def connect_nt(self, p):
connections = [(begin, p.NAME) for begin in p.any]
return connections
@_('NAME "<" any')
def connect_nt(self, p):
connections = [(begin,p.NAME) for begin in p.any]
return connections
@_('NAME')
def any(self, p):
return [p.NAME]
@_('NAME "," any')
def any(self, p):
(p.any).append(p.NAME)
return p.any
def error(self, p):
if p:
print(f"Syntax error at token {p.type} ({p.value}), line {p.lineno}")
else:
print("Unexpected end of input")
def run_main(input, output):
lexer = BlockLexer()
parser = BlockParser()
with open(input, "r") as f:
data = f.read()
elements = parser.parse(lexer.tokenize(data))
elements.reverse()
nodes = [node for node in elements if isinstance(node,Block)]
to_write = ""
for elem in elements:
to_write+=elem.to_string(nodes)
if EXCEPT:
print(EXCEPT)
return False
with open(output, 'w') as f:
f.write("digraph BlockSchema {\n")
f.write("node [style=filled]; \n")
f.write(to_write)
f.write("}\n")
return True