-- Copyright 2017 Marcio Baraco . See LICENSE. -- Postscript LPeg lexer. local l = require('lexer') local token, word_match = l.token, l.word_match local P, R, S = lpeg.P, lpeg.R, lpeg.S local M = {_NAME = 'ps'} -- Whitespace. local ws = token(l.WHITESPACE, l.space^1) -- Comments. local comment = token(l.COMMENT, '%' * l.nonnewline^0) -- Strings. local nested_string = l.delimited_range('()', false, false, true) local hex_string = P('<') * (l.xdigit + l.space)^0 * P('>')^-1 local enc_string = P('<~') * (R('!u') + l.space)^0 * P('~>') local str = token(l.STRING, nested_string + hex_string + enc_string) -- Numbers. local frac = (P('.') * l.digit^1) local expo = (S('eE') * S('+-')^-1 * l.digit^1) local decm = S('+-')^-1 * l.digit ^ 1 * frac^-1 * expo^-1 local radx = l.digit^-2 * '#' * l.alnum^1 -- TODO: Accept only chars that fit radix, ie [01] for 2#, hex for 16# and so. local number = token(l.NUMBER, decm + radx) -- PostScript allows almost all characters in names. local word = (l.graph - S('()<>[]{}/%'))^1 -- Names. local identifier = token(l.IDENTIFIER, word) -- Deferred Names. local label = token(l.LABEL, '/' * word) -- Immediately Evaluated Names. local preproc = token(l.PREPROCESSOR, '//' * word) -- Object constructors. local operator = token(l.OPERATOR, S('[]{}=') + P('<<') + P('>>') + P('==')) -- Operators: -- + l.KEYWORD for basic ops -- + l.FUNCTION for graphic ops -- + l.CLASS for weird ps ops local keyword = token(l.KEYWORD, word_match{ -- Control operators. 'exec', 'eexec', 'if', 'ifelse', 'for', 'repeat', 'loop', 'exit', 'stop', 'stopped', 'countexecstack', 'execstack', 'quit', 'start', -- Stack manipulation operators. 'pop', 'exch', 'dup', 'copy', 'index', 'roll', 'clear', 'count', 'mark', 'cleartomark', 'counttomark', -- Array and operators. 'array', 'string', 'length', 'get', 'put', 'getinterval', 'putinterval', 'aload', 'astore', 'packedarray', 'setpacking', 'currentpacking', 'forall', 'anchorsearch', 'search', 'token', -- Dictionary operators. 'dict', 'maxlength', 'begin', 'end', 'def', 'undef', 'load', 'store', 'known', 'where', 'currentdict', 'errordict', 'systemdict', 'userdict', 'globaldict', 'shareddict', 'statusdict', 'countdictstack', 'cleardictstack', 'dictstack', -- Type, attribute and conversion operators. 'type', 'cvlit', 'cvx', 'cvi', 'cvn', 'cvrs', 'cvs', 'cvr', 'xcheck', 'executeonly', 'noaccess', 'readonly', 'rcheck', 'wcheck', -- Arithmetic and math operators. 'add', 'div', 'idiv', 'mod', 'mul', 'sub', 'abs', 'neg', 'ceiling', 'floor', 'round', 'truncate', 'sqrt', 'atan', 'cos', 'sin', 'exp', 'ln', 'log', 'rand', 'srand', 'rrand', -- Relational, boolean and bitwise operators. 'eq', 'ne', 'ge', 'gt', 'le', 'lt', 'and', 'not', 'or', 'xor', 'true', 'false', 'bitshift', -- Coordinate system and matrix operators. 'matrix', 'initmatrix', 'identmatrix', 'defaultmatrix', 'currentmatrix', 'setmatrix', 'translate', 'scale', 'rotate', 'concat', 'concatmatrix', 'transform', 'dtransform', 'itransform', 'idtransform', 'invertmatrix', }) local func = token(l.FUNCTION, word_match{ -- Path construction operators. 'newpath', 'currentpoint', 'moveto', 'rmoveto', 'lineto', 'rlineto', 'arc', 'arcn', 'arct', 'arcto', 'curveto', 'rcurveto', 'closepath', 'flattenpath', 'reversepath', 'strokepath', 'ustrokepath', 'charpath', 'uappend', 'clippath', 'setbbox', 'pathbbox', 'pathforall', 'upath', 'ucache', 'initclip', 'clip', 'eoclip', 'rectclip', -- Glyph and font operators. 'definefont', 'composefont', 'undefinefont', 'findfont', 'scalefont', 'makefont', 'setfont', 'rootfont', 'currentfont', 'selectfont', 'show', 'ashow', 'widthshow', 'awidthshow', 'xshow', 'yshow', 'xyshow', 'glyphshow', 'stringwidth', 'cshow', 'kshow', 'findencoding', 'FontDirectory', 'GlobalFontDirectory', 'SharedFontDirectory', 'StandardEncoding', 'ISOLatin1Encoding', 'setcachedevice', 'setcachedevice2', 'setcharwidth', -- CID Font operators. 'addglyph', 'beginbfchar', 'beginbfrange', 'begincidchar', 'begincidrange', 'begincmap', 'begincodespacerange', 'beginnotdefchar', 'beginnotdefrange', 'beginrearrangedfont', 'beginusematrix', 'endbfchar', 'endbfrange', 'endcidchar', 'endcidrange', 'endcmap', 'endcodespacerange', 'endnotdefchar', 'endnotdefrange', 'endrearrangedfont', 'endusermatrix', 'removeall', 'removeglyphs', 'StartData', 'usecmap', 'usefont', -- Painting operations. 'erasepage', 'stroke', 'fill', 'eofill', 'rectstroke', 'rectfill', 'ustroke', 'ufill', 'ueofill', 'shfill', 'image', 'imagemask', 'colorimage', -- Insideness testing operators. 'infill', 'ineofill', 'inufill', 'inueofill', 'instroke', 'inustroke', -- Form and pattern operators. 'makepattern', 'setpattern', 'execform', -- Graphics state operators. 'gsave', 'grestore', 'clipsave', 'cliprestore', 'grestoreall', 'initgraphics', 'gstate', 'setgstate', 'currentgstate', 'setlinewidth', 'currentlinewidth', 'setlinecap', 'currentlinecap', 'setlinejoin', 'currentlinejoin', 'setmiterlimit', 'currentmiterlimit', 'setstrokeadjust', 'currentstrokeadjust', 'setdash', 'currentdash', 'setcolorspace', 'currentcolorspace', 'setcolor', 'setgray', 'currentgray', 'sethsbcolor', 'currenthsbcolor', 'setrgbcolor', 'currentrgbcolor', 'setcmykcolor', 'currentcmykcolor', 'sethalftone', 'currenthalftone', 'setscreen', 'currentscreen', 'setcolorscreen', 'currentcolorscreen', 'settransfer', 'currenttransfer', 'setcolortransfer', 'currentcolortransfer', 'setblackgeneration', 'currentblackgeneration', 'setundercolorremoval', 'currentundercolorremoval', 'setcolorrendering', 'currentcolorrendering', 'setflat', 'currentflat', 'setoverprint', 'currentoverprint', 'setsmoothness', 'currentsmoothness', 'currentcolor', -- Device setup operators. 'showpage', 'copypage', 'setpagedevice', 'currentpagedevice', 'nulldevice', 'currenttrapparams', 'settrapparams', 'settrapzone', }) local misc = token(l.CLASS, word_match{ -- Miscellaneous operators 'defineresource', 'undefineresource', 'findresource', 'findcolorrendering', 'resourcestatus', 'resourceforall', 'GetHalftoneName', 'GetPageDeviceName', 'GetSubstituteCRD', 'save', 'restore', 'setglobal', 'setshared', 'currentglobal', 'gcheck', 'scheck', 'startjob', 'defineuserobject', 'execuserobject', 'undefineuserobject', 'UserObjects', 'bind', 'null', 'version', 'realtime', 'usertime', 'languagelevel', 'product', 'revision', 'serialnumber', 'executive', 'echo', 'prompt', 'setsystemparams', 'currentsystemparams', 'setuserparams', 'currentuserparams', 'setdevparams', 'currentdevparams', 'vmreclaim', 'setvmthreshold', 'vmstatus', 'cachestatus', 'setcachelimit', 'setcacheparams', 'currentcacheparams', 'setucacheparams', 'ucachestatus', 'currentshared', 'exitserver', 'serverdict', -- File operators 'file', 'filter', 'closefile', 'read', 'write', 'readhexstring', 'writehexstring', 'readstring', 'writestring', 'readline', 'bytesavailable', 'flush', 'flushfile', 'resetfile', 'status', 'run', 'currentfile', 'deletefile', 'renamefile', 'filenameforall', 'setfileposition', 'fileposition', 'print', 'stack', 'pstack', 'printobject', 'writeobject', 'setobjectformat', 'currentobjectformat', -- Errors. 'configurationerror', 'dictfull', 'dictstackoverflow', 'dictstackunderflow', 'execstackoverflow', 'handleerror', 'interrupt', 'invalidaccess', 'invalidexit', 'invalidfileaccess', 'invalidfont', 'invalidrestore', 'ioerror', 'limitcheck', 'nocurrentpoint', 'rangecheck', 'stackoverflow', 'stackunderflow', 'syntaxerror', 'timeout', 'typecheck', 'undefined', 'undefinedfilename', 'undefinedresource', 'undefinedresult', 'unmatchedmark', 'unregistered', 'VMerror', }) M._rules = { {'whitespace', ws}, {'comment', comment}, {'number', number}, {'preprocessor', preproc}, {'label', label}, {'keyword', keyword}, {'function', func}, {'class', misc}, {'operator', operator}, {'string', str}, {'identifier', identifier}, } return M