What does parse mean?
How do we parse PSYC?
- You need two hashes, one for current variables, one for permanent ones. I'll call them cvars and pvars.
- You can save the object pointer of the current parser at creation time into an internal permanent variable, like this: pvars["_INTERNAL_origin"] = this;
- Receive an empty packet first. It's a dot (old) or pipe (new) on a line by itself.
- LOOP TOP: Enter the packet parsing loop.
- First thing you do is put a copy of the pvars into the cvars (careful to copy the actual data structures, not the reference).
- Look at your input line by line.
- Look at the first character on the line, is it an operator glyph?
- Handle the temporary variable prefixed by ":": Put the value into the appropriate cvars.
- Handle persistent variables prefixed by "=": Put its name and value into both pvars and cvars.
- Handle "+" by appending the value to the existing value, then copy it to both pvars and cvars. In fact the + and - operation changes depending on variable type, but we aren't using this yet.
- Handle "-" by removing the appropriate variable from both pvars and cvars. Real subtraction isn't defined yet, and we aren't using it.
- Ignore lines that start with "?", "!" or other as yet undefined glyph.
- You should encounter an empty line which separates PSYC's routing layer from PSYC's end-to-end layer (we call it entity layer). If the routing vars contained the _length variable, you should read that number of bytes into a buffer - it will contain the rest of the packet: entity vars, the method and the body. So in that case continue working with the buffer. Oh, while you're at it, make sure the following bytes after the buffer are the end-of-packet marker.
- If you are not the intended recipient of the packet (which you can now tell by looking at the routing header) you must have taken up the role of a router. You can now choose to route the packet without parsing the rest of it. If no content-length was given you will have to scan for the end-of-packet marker, which is a dot (old) or pipe (new) on a line by itself.
- Now you are in the entity header. You should again receive lines that begin with an operator, a variable name and optionally their value.
- Should you encounter any alphanumeric character, or the underscore "_", that's the method.
- Right after finding the method, stop looking at line beginnings, break out of your header parsing loop.
- If a content-length was given, the rest of the buffer will be your body. Otherwise put every following line of data into the body until you hit the terminating "." or "|" on its line by itself.
- Dispatch the newly parsed packet: Pass the method, body and cvars to the API. Routing and entity vars are usually merged at this point, since we are done routing.
- Now you can start your LOOP again from its TOP.
In order to support the old syntax what's missing here is list and line continuations.
For the new PSYC syntax you need to parse length-prefixed variables according to Spec:Packet instead of the obsoleted line and list continuations. And the new list syntaxes, of course.
<coyo> The syntax is rather beautiful, isnt it? ;3
Let's look at some more parsers. Many of them are unfinished/prototypical, so use with care. Our web server however does not do any syntax highlighting. You may want to store the files and view them with your best editing technology. For LPC highlighting tips look here.
- libpsyc in C, supposed to be linked into other languages for unified high speed parsing.
- Saikound in D.
- mjacob's current pypsyc.
- psycpp's C and C++ parser.
- the net/spyc parser in psyced (to be replaced by libpsyc)
- ActionScript reference parser from psycTiVE.
- jaPSYC's MMPInput.java
- perlpsyc's Net::PSYC.pm (look for parse_psyc)
- ppp's MMP.pmod (look for MMP.Parse deep inside)
- PsycM's parse.cc
- PsycZilla's socket.js (look for ParseMessage)
- psyced's parse.i (messy! too much experimental code in ifdefs like FORK)
- psyconaut's Parser.cs
- old pypsyc's PSYCProtocol.py
- fippo's State.py (twisted state machine)
- mllp's PSYCParser.java
- the other libPSYC has a Parser.cpp in C++