Ignore:
Timestamp:
09/11/09 03:22:41 (10 years ago)
Author:
bretzel_parpg
Message:

Patch by Bretzel.

  • Wrote a parser for the new syntax I developed (I will post about this at the forums in the Dialog System Implementation thread)
  • Started to add a dialogue map, which will show you the flow of the dialogue
  • Overrode the resize event in the application so that it will also resize the editor and dialog map
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tools/writing_editor/scripts/parser.py

    r251 r280  
    1616#   along with PARPG.  If not, see <http://www.gnu.org/licenses/>. 
    1717 
    18 import re 
    19 from lib.pyparsing import * 
    2018from PyQt4 import QtGui, QtCore 
    2119 
    22 class Parser(): 
     20# goto_table stores label's so you can jump back to them 
     21# they are stored in the format: {label (string): paragraph number (int, starts at 0)} 
     22goto_table = {} 
     23 
     24class ConversationNode(object): 
    2325    """ 
    24     The parser 
     26    The class for every node in the conversation tree 
    2527    """ 
    26     def __init__(self, widget, result_function): 
     28    def __init__(self, label="", text="", type_="", options=[]): 
    2729        """ 
    28         Initialize the parser 
    29         @type document: QtGui.QTextEdit 
    30         @param document: The QTextEdit 
    31         @type result_function: function 
    32         @param result_function: the function that handles the results 
     30        Initialize the node 
     31        @type label: string 
     32        @param label: the label for the node 
     33        @type text: string 
     34        @param text: the text for the node 
     35        @type type_: string 
     36        @param type_: the type of node, either 'text' or 'option' 
     37        @type options: list 
     38        @param options: a list of all the option nodes 
    3339        @return: None 
    3440        """ 
    35         self.widget = widget 
    36         self.resultFunction = result_function 
    37         self.makeFunctions() 
    38         self.funcs = ["SCRIPTNAME", "NPC", "CALLSECTION", "ENDSECTION", "SECTION",  
    39                       "SCRIPTNAME", "ENDOPTION", "OPTION", "PLAYSOUND",  
    40                       "SAY", "ATTACK", "RETURN", "ELIF", "IF", "ELSE", "PC", "."] 
    41  
    42         self.func_by_name = {"NPC":self.npc, "PC":self.pc, "CALLSECTION":self.callsection, 
    43                              "ENDSECTION":self.endsection, "SECTION": self.section, 
    44                              "SCRIPTNAME":self.scriptname, "ENDOPTION":self.endoption, 
    45                              "OPTION":self.option, "PLAYSOUND":self.playsound, 
    46                              "SAY":self.say, "ATTACK":self.attack, "RETURN":self.return_, 
    47                              "ELIF":self.elif_, "IF":self.if_, "ELSE":self.else_, 
    48                              ".":self.option_item} 
     41        self.label = label 
     42        self.text = text 
     43        self.type_ = type_ 
     44        self.options = options 
    4945 
    5046 
    51     def makeFunctions(self): 
    52         """ 
    53         Setup all the matching functions 
    54         @return: None 
    55         """ 
    56         self.text = Word(alphanums) 
    57         self.nums = Word(nums) 
    58         self.period = Literal(".") 
    59         self.space = Literal(" ") 
    60         self.colon = Literal(":") 
    61         self.quote = Literal("\"") 
     47def parse(text): 
     48    """ 
     49    Parse the text and create the tree structure from it 
     50    @type text: string 
     51    @param text: the text to parse 
     52    @return: the root node 
     53    """ 
     54    text = str(text).strip() 
    6255 
    63         self.npc = Combine(Word("NPC") + self.space + self.text) 
    64         self.pc = Word("PC") 
    65         self.section = Combine(Word("SECTION") + self.space + self.text) 
    66         self.endsection = Word("ENDSECTION") 
    67         self.callsection = Combine(Word("CALLSECTION") + self.space + self.text) 
    68         self.scriptname = Combine(Word("SCRIPTNAME") + self.space + self.text) 
    69         self.option = Combine(Word("OPTION") + self.space + self.text) 
    70         self.option_item = Combine(self.nums + Optional(self.space) + self.period + Optional(self.space) + self.text) 
    71         self.endoption = Combine(Word("ENDOPTION") + self.space + self.text) 
    72         self.playsound = Combine(Word("PLAYSOUND") + self.space + self.quote + self.text + self.quote) 
    73         self.say = Combine(self.text + self.space + Word("SAY") + self.space + self.quote  
    74                            + self.text + self.quote) 
    75         self.attack = Combine(self.text + self.space + Word("ATTACK") + self.space + self.text) 
    76         self.return_ = Combine(Word("RETURN") + self.space + self.text) 
    77         self.if_ = Combine(Word("IF") + self.space + self.text + self.colon) 
    78         self.elif_ = Combine(Word("ELIF") + self.space + self.text + self.colon) 
    79         self.else_ = Combine(Word("ELSE") + self.colon) 
     56    if (text == ""): 
     57        # if there is no text return an empty node 
     58        return ConversationNode() 
    8059 
    81          
    82     def findType(self, string): 
    83         """ 
    84         Find the type of command that is in the string given 
    85         @type string: string 
    86         @param string: the string to find the type of 
    87         @return: the type 
    88         """ 
    89         type_ = None 
    90         for func in self.funcs: 
    91             regex = re.compile(func + "{0,1}") 
    92             if (regex.search(str(string)) != None): 
    93                 type_ = func 
    94                 break 
     60    # split the text into paragraphs 
     61    paras = [] 
     62    for line in text.split('\n'): 
     63        line = line.strip() 
     64        if line != "": 
     65            paras.append(line)  
     66             
     67    # if there is a label make sure to have it in the same paragraph as it's text 
     68    for para in paras: 
     69        if para.startswith("LABEL"): 
     70            para_spot = paras.index(para) 
     71            next_para = paras[para_spot+1] 
     72            new_para = para + '\n' + next_para 
    9573 
    96         return type_ 
     74            paras.remove(para) 
     75            paras.remove(next_para) 
     76            paras.insert(para_spot, new_para) 
    9777 
    98     def parse(self): 
    99         """ 
    100         Parse the text 
    101         @return: the parsed text 
    102         """         
    103         doc = self.widget.document().toPlainText() 
    104         if (doc == ""): 
    105             return 
     78    # recursively parse the text and get the root node and end 
     79    root, end = _parse(paras, 0, len(paras)-1) 
     80     
     81    # if the end is not the end of the paragraphs, then throw a syntax error 
     82    if (end != len(paras)): 
     83        print "syntax error 1" 
    10684 
    107         for line in doc.split('\n'): 
    108             if (line == ""): 
    109                 continue 
    110  
    111             line_type = self.findType(line) 
    112             try: 
    113                 command = self.func_by_name[line_type] 
    114             except KeyError, e: 
    115                 self.createErrorBox(e) 
    116                 return 
    117  
    118             parse = command.scanString(line) 
    119             for result in parse: 
    120                 self.resultFunction(result[0][0], line_type) 
     85    # else return the root node 
     86    else: 
     87        return root 
    12188 
    12289 
    123     def createErrorBox(self, error): 
    124         """ 
    125         Create an error box saying that the text couldn't be parsed 
    126         @type error: KeyError 
    127         @param error: The error that was generated 
    128         @return: None 
    129         """ 
    130         msg_box = QtGui.QMessageBox() 
    131         msg_box.setText("Error while parsing") 
    132         msg_box.setInformativeText("Could not find the type \"%s\" in self.func_by_name" % str(error)) 
    133         msg_box.setStandardButtons(QtGui.QMessageBox.Ok) 
    134         msg_box.setWindowTitle("Error") 
    135         msg_box.setWindowIcon(QtGui.QIcon("data/images/error.png")) 
    136          
    137         ret = msg_box.exec_() 
    138         if (ret == QtGui.QMessageBox.Ok): 
    139             msg_box.close() 
     90def _parse(paras, start, end): 
     91    """ 
     92    Recursively parse the text 
     93    @type paras: list 
     94    @param paras: a list of the paragraphs in the text 
     95    @type start: int 
     96    @param start: the start of the text 
     97    @type end: int 
     98    @param end: the end of the text 
     99    @return: the root node and end of text 
     100    """ 
     101    # create a new node 
     102    node = ConversationNode() 
     103 
     104    # check for a label and extract it if its there 
     105    if (paras[0].startswith("LABEL")): 
     106        label_text = paras[0].split('\n')[0][6:] 
     107        node.label = label_text 
     108        goto_table[label_text] = 0 
     109        paras[0] = paras[0].split('\n')[1] 
     110 
     111    for i in xrange(start, end): 
     112        # if the paragraph is an option, break the loop 
     113        if (paras[i].startswith("OPTION")): 
     114            break 
     115 
     116        # if the paragraph is an endoption, exit the function and return the node and the end point 
     117        elif (paras[i].startswith("ENDOPTION")): 
     118            return node, i 
     119 
     120        # else parse the text normally 
     121        else: 
     122            node.type = 'text' 
     123            node.text = paras[i] 
     124             
     125    # while not at the end of the text 
     126    while i < end: 
     127        # if the paragraph is an option, start the recursive parsing and append the option to the root node 
     128        if (paras[i].startswith("OPTION")): 
     129            txt = paras[i][7:] 
     130            child, i = _parse(paras, i+1, end) 
     131            child.type_ = 'option' 
     132            child.text = txt 
     133            node.options.append(child) 
     134             
     135        # if the paragraph is an endoption, it is a syntax error 
     136        elif (paras[i].startswith("ENDOPTION")): 
     137            print "syntax error 2" 
     138 
     139        # move to the next paragraph 
     140        i += 1 
     141 
     142    return node, i 
Note: See TracChangeset for help on using the changeset viewer.