# -*- coding: utf-8 -*- # lp4all: literate programming embedded in source code as wiki comments # Copyright (C) 2006 Jean-Marie Favreau, Frédéric Lehobey, David Mentré # and Thomas Petazzoni # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import sys try: import lex import yacc except ImportError: try: from ply import lex from ply import yacc except ImportError: print "python-ply is required, please install." sys.exit (1) from iface import * from tree_struct import * from parse_exception import *
class SimpleParser: def __init__(self, debug = 0): # build lex/yacc objects self.lexer = lex.lex(module=self, debug = debug, lextab = "slextab") self.yacc = yacc.yacc(module=self, debug = debug, tabmodule = "sparsetab") def trace(self, text): #print text pass tokens = ( 'TEXT', 'SPECIALCHAR', 'CODE', 'STRONG', 'CANCEL', 'EM', 'REF','LINK', 'TEXT_IN_LINK', 'ENDLINK', 'LABEL' ) def t_STRONG(self, t): r'\*\*(\*?[^\*])*\*\*' return t def t_CANCEL(self, t): r'~~(~?[^~])*~~' t.lineno += t.value.count("\n") return t def t_EM(self, t): r'\/\/(\/?[^\/])*\/\/' t.lineno += t.value.count("\n") return t def t_ENDLINK(self, t): r'\]\]' return t def t_CODE(self, t): r'\^\^(\^?[^\^])*\^\^' t.lineno += t.value.count("\n") return t def t_REF(self, t): r'\[\[\#[^]\#@\|]+' t.lineno += t.value.count("\n") return t def t_LINK(self, t): r'\[\[[^]\ \|]+' t.lineno += t.value.count("\n") return t def t_LABEL(self, t): r'\[@[^]\#@\|]+@\]' t.lineno += t.value.count("\n") return t def t_TEXT(self, t): r'[^]%\/\*\[@=\#\^~\|]+' t.lineno += t.value.count("\n") return t def t_TEXT_IN_LINK(self, t): r'\|(\]?[^]]+)+' t.lineno += t.value.count("\n") return t def t_SPECIALCHAR(self, t): r'[%\/\*\[=\]#@~^\|]' return t def t_error(self, t): print "Illegal character '%s' (line %s" % (t.value[0], t.lineno) t.skip(1) # expression line def p_expressionline_sp_start(self, p): '''statement : SPECIALCHAR expression''' p[0] = NodeContentText(children = [NodeContentText(p[1]), p[2]]) def p_expressionline_sp_end(self, p): '''statement : expression SPECIALCHAR''' p[0] = NodeContentText(children = [p[1], NodeContentText(p[2])]) def p_expressionline(self, p): '''statement : expression''' p[0] = p[1] # only one special char def p_expression_addspecialchar(self, p): '''expression : expression SPECIALCHAR expression''' self.trace("special char: " + p[2]) p[0] = NodeContentText(children = [p[1], NodeContentText(p[2]), p[3]]) # define expression properties def p_expression_expression(self, p): 'expression : expression expression' p[0] = NodeContentText(children = [p[1], p[2]]) def p_expression_strong(self, p): 'expression : STRONG' p[0] = NodeContentStrong(children = [self.childrenParser.parseSimpleComment(content = p[1][2:][:-2], lineno = p.lineno(1))]) def p_expression_cancel(self, p): 'expression : CANCEL' p[0] = NodeContentCancel(children = [self.childrenParser.parseSimpleComment(content = p[1][2:][:-2], lineno = p.lineno(1))]) def p_expression_em(self, p): 'expression : EM' p[0] = NodeContentEmphasize(children = [self.childrenParser.parseSimpleComment(content = p[1][2:][:-2], lineno = p.lineno(1))]) # code def p_block_code(self, p): 'expression : CODE' self.trace("code: " + p[1][2:][:-2] + "\n\n") p[0] = NodeContentCode(text = p[1][2:][:-2]) def p_expression_all(self, p): '''expression : TEXT''' p[0] = NodeContentText(text = p[1]) # link def p_block_link_expr(self, p): '''expression : LINK TEXT_IN_LINK ENDLINK''' self.trace("link (+): " + p[1][2:]) p[0] = NodeContentLink(uri = p[1][2:], children = [self.childrenParser.parseSimpleComment(content = p[2][1:], lineno = p.lineno(2))]) def p_block_link(self, p): '''expression : LINK ENDLINK''' self.trace("link: " + p[1][2:]) p[0] = NodeContentLink(uri = p[1][2:]) # ref def p_block_ref_expr(self, p): '''expression : REF TEXT_IN_LINK ENDLINK''' self.trace("ref (+): " + p[1][3:]) p[0] = NodeContentRef(ref = p[1][3:], children = [self.childrenParser.parseSimpleComment(content = p[2][1:], lineno = p.lineno(2))]) def p_block_ref(self, p): '''expression : REF ENDLINK''' self.trace("ref: " + p[1][3:]) p[0] = NodeContentRef(ref = p[1][3:]) # label def p_block_label(self, p): '''expression : LABEL''' self.trace("label " + p[1][2:][:-2]) p[0] = NodeContentLabel(label = p[1][2:][:-2]) def p_error(self, p): try: raise ParseException("Syntax error at '%s'" % p.value, p.lineno) except AttributeError: raise ParseException("Syntax error", self.lineno, self.lineno + self.nbline) # parse a simple comment and build associated nodes def parseSimpleComment(self, content, debug = 0, lineno = 1, endlineno = 1): # if parser for children (recursive pass) has not been built, create it if not 'childrenParser' in self.__dict__: self.childrenParser = SimpleParser(debug = debug) # init lineno self.lexer.lineno = lineno self.lineno = lineno self.nbline = content.count("\n") # run parser return self.yacc.parse(content, debug = debug, lexer = self.lexer)