Skip to content

Instantly share code, notes, and snippets.

Created December 23, 2016 09:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/f7fee82634ba224e25e9022ec2c3c890 to your computer and use it in GitHub Desktop.
Save anonymous/f7fee82634ba224e25e9022ec2c3c890 to your computer and use it in GitHub Desktop.
PLY Stanford polygon file format parser with pyparsing
# -*- coding: utf-8 -*-
"""
Parse PLY Stanford Polygon Files
--------------------------------
Context free grammar:
ply_grammar ::= header body
header ::= "ply" declaration+ "end_header"
declaration ::= format | element | property
format ::= "format" format_type NUMBER
element ::= "element" element_type NUMBER
property ::= ("property" property_type IDENT) | ("property" "list" property_type property_type IDENT)
format_type ::= "ascii" | "binary_little_endian" | "binary_big_endian"
element_type ::= "vertex" | "face" | "edge" | IDENT
property_type ::= "char" | "uchar" | "short" | "ushort" | "int" | "uint" | "float" | "double"
body ::= statement+
statement ::= NUMBER+
"""
import pathlib
import pyparsing as pp
number = pp.pyparsing_common.number()
identifier = pp.pyparsing_common.identifier()
lit = {l: pp.CaselessLiteral(l) for l in (
"ascii", "binary_little_endian", "binary_big_endian", "vertex", "face", "edge", "char",
"uchar", "short", "ushort", "int", "uint", "float", "double", "format", "comment",
"element", "property", "list", "ply", "end_header"
)}
format_type = lit["ascii"] | lit["binary_little_endian"] | lit["binary_big_endian"]
element_type = lit["vertex"] | lit["face"] | lit["edge"] | identifier
property_type = lit["char"] | lit["uchar"] | lit["short"] | lit["ushort"] | lit["int"] | lit["uint"] | lit["float"] | lit["double"]
format_decl = pp.Suppress(lit["format"]) + format_type.setResultsName("file_type") + number.setResultsName("version")
comment_decl = lit["comment"] + pp.restOfLine
element_decl = pp.Suppress(lit["element"]) + element_type.setResultsName("name") + number.setResultsName("number")
property_decl = pp.Suppress(lit["property"]) + (
(property_type.setResultsName("data_type") + identifier.setResultsName("name")) |
(pp.Suppress(lit["list"]) + property_type.setResultsName("idx_type") + property_type.setResultsName("data_type") + identifier.setResultsName("name"))
)
declarations = format_decl.setResultsName("format") + pp.OneOrMore(pp.Group(
element_decl + pp.OneOrMore(pp.Group(property_decl))
)).setResultsName("declarations")
header = pp.Suppress(lit["ply"]) + declarations + pp.Suppress(lit["end_header"])
body = pp.OneOrMore(number)
ply_grammar = header.setResultsName("header") + body.setResultsName("body")
ply_grammar.ignore(comment_decl)
def main():
data = """ply
format ascii 1.0
comment made by Greg Turk
comment this file is a cube
element vertex 8
property float x
property float y
property float z
element face 6
property list uchar int vertex_index
end_header
0 0 0
0 0 1
0 1 1
0 1 0
1 0 0
1 0 1
1 1 1
1 1 0
4 0 1 2 3
4 7 6 5 4
4 0 4 5 1
4 1 5 6 2
4 2 6 7 3
4 3 7 4 0
"""
try:
ply_grammar.validate()
tokens = ply_grammar.parseString(data)
print(tokens)
except pp.ParseException as e:
print(e.line)
print(" " * (e.column - 1) + "^")
print(e)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment