import pprint from dataclasses import dataclass from typing import List, Tuple from sly import Lexer, Parser @dataclass class Vertex: coords: Tuple[float, float, float] def __repr__(self): return "VERTEX(%f,%f,%f)" % self.coords @dataclass class Facet: vertices: Tuple[Vertex, Vertex, Vertex] normal: Vertex def __repr__(self): return "\t FACET({normal})\n\t\t{vertices}".format( normal=repr(self.normal), vertices="\n\t\t".join(repr(vertex) for vertex in self.vertices) ) @dataclass class Solid: name: str facets: List[Facet] def __repr__(self): return "SOLID({name})\n{facets}\n".format( name=self.name, facets="\n".join(repr(facet) for facet in self.facets) ) class STLLexer(Lexer): tokens = {"SOLID_START", "SOLID_END", "FACET_START", "FACET_END", "NAME_LITERAL", "LOOP_START", "LOOP_END", "NAME_LITERAL", "VERTEX_TAG", "FLOAT"} @_(r"[ \t\n]+") def ignore_whitespace(self, t): self.lineno += t.value.count("\n") SOLID_START = r"solid" SOLID_END = r"endsolid" FACET_START = r"facet normal" FACET_END = r"endfacet" LOOP_START = r"outer loop" LOOP_END = r"endloop" VERTEX_TAG = r"vertex" @_("[+-]?\d+(\.\d*(e[+-]?\d+)?)?") def FLOAT(self, t): t.value = float(t.value) return t NAME_LITERAL = r"\w+" class STLParser(Parser): tokens = STLLexer.tokens start = "stl" @_("solid") def stl(self, p): return p.solid @_("SOLID_START NAME_LITERAL facets_list SOLID_END") @_("SOLID_START NAME_LITERAL facets_list SOLID_END NAME_LITERAL") def solid(self, p): return Solid(name=p[1], facets=p.facets_list) @_("facet") def facets_list(self, p): return [p.facet] @_("facet facets_list") def facets_list(self, p): return [p.facet] + p.facets_list @_("FACET_START triplet loop FACET_END") def facet(self, p): return Facet(vertices=p.loop, normal=Vertex(p.triplet)) @_("LOOP_START vertex vertex vertex LOOP_END") def loop(self, p): return p[1], p[2], p[3] @_("VERTEX_TAG triplet") def vertex(self, p): return Vertex(p.triplet) @_("FLOAT FLOAT FLOAT") def triplet(self, p): return p[0], p[1], p[2] def error(self, token): pass if __name__ == "__main__": lexer = STLLexer() parser = STLParser() with open("star.stl") as stl_file: # pprint.pprint(list(lexer.tokenize(stl_file.read()))) solid = parser.parse(lexer.tokenize(stl_file.read())) print(solid)