1 
     2 /*
     
3 
     4 This is the grammar for Hootscript.  This script also makes some transformations
     
5 to the grammar so that it contains predictions (instead of a separate prediction
     
6 table as you might expect).
     
7 
     8 This grammar is used by the Hoot parser to transform scripts into games.
     
9 
    10 */
    
11 
    12 
    13 function getGrammar(){
    
14 
    15     // the grammar
    
16     // =====================================================================
    
17 
    18 
    19     var grammar = {
    
20         "script":   { rules: "+func",                                          keep:true },
    
21         "func":     { rules: "name colon +expr",                               keep:true },
    
22         "expr":     { rules: "print | assign | ifseq | runme | incr | decr"              },
    
23         "print":    { rules: "qopen *qinnards qclose",                         keep:true },
    
24         "assign":   { rules: "set name to num",                                keep:true },
    
25         "qinnards": { rules: "strname | upname | break | link | string"                  },
    
26         "ifseq":    { rules: "if value test value then +expr *elseseq end",    keep:true },
    
27         "elseseq":  { rules: "else +expr",                                     keep:true },
    
28         "test":     { rules: "eq | lt | gt | de"                                         },
    
29         "value":    { rules: "name | num"                                                },
    
30         "cond":     { rules: "if value test value then +expr",                 keep:true },
    
31         "runme":    { rules: "run name",                                       keep:true },
    
32         "incr":     { rules: "increase name",                                  keep:true },
    
33         "decr":     { rules: "decrease name",                                  keep:true },
    
34         "colon":    { lookahead: /^:/,        extract: /^(:)\s*/                         },
    
35         "name":     { lookahead: /^\[/,       extract: /^\[([^[_]+?)\]\s*/,    keep:true },
    
36         "num":      { lookahead: /^\d/,       extract: /^(\d+)\s*/,            keep:true },
    
37         "eq":       { lookahead: /^e/,        extract: /^(equals)\s*/,         keep:true },
    
38         "lt":       { lookahead: /^l/,        extract: /^(less than)\s*/,      keep:true },
    
39         "gt":       { lookahead: /^g/,        extract: /^(greater than)\s*/,   keep:true },
    
40         "de":       { lookahead: /^d/,        extract: /^(doesn't equal)\s*/,  keep:true },
    
41         "set":      { lookahead: /^s/,        extract: /^(set)\s*/                       },
    
42         "to":       { lookahead: /^t/,        extract: /^(to)\s*/                        },
    
43         "if":       { lookahead: /^if/,       extract: /^(if)\s*/                        },
    
44         "then":     { lookahead: /^t/,        extract: /^(then)\s*/                      },
    
45         "else":     { lookahead: /^el/,       extract: /^(else)\s*/                      },
    
46         "end":      { lookahead: /^en/,       extract: /^(end)\s*/                       },
    
47         "run":      { lookahead: /^r/,        extract: /^(run)\s*/                       },
    
48         "increase": { lookahead: /^in/,       extract: /^(increase)\s*/                  },
    
49         "decrease": { lookahead: /^de/,       extract: /^(decrease)\s*/                  },
    
50         "qopen":    { lookahead: /^\//,       extract: /^(\/)/                           },
    
51         "qclose":   { lookahead: /^\//,       extract: /^(\/)\s*/                        },
    
52         "string":   { lookahead: /^[^\/^[_]/, extract: /^((?:\\.|[^\/[_^])+)/, keep:true },
    
53         "link":     { lookahead: /^_/,        extract: /^_([^_]+?)_/,          keep:true },
    
54         "break":    { lookahead: /^__/,       extract: /^(__)/,                keep:true },
    
55         "strname":  { lookahead: /^\[/,       extract: /^\[([^[]+?)\]/,        keep:true },
    
56         "upname":   { lookahead: /^\^\[/,     extract: /^\^\[(.+?)\]/,         keep:true }
    
57     };
    
58 
    59 
    60 
    61 
    62     // massage the grammar
    
63     // =====================================================================
    
64 
    65     for(var g in grammar){ 
    
66         atom = grammar[g];
    
67         atom.name = g; // store its name inside itself
    
68         atom.operator = ""; // default
    
69 
    70         if(atom.rules){
    
71             // split alternative rules
    
72             atom.rules = atom.rules.split(" | ");
    
73             for(r in atom.rules){
    
74                 // split rule into atoms
    
75                 atom.rules[r] = atom.rules[r].split(" ");
    
76                 for(x in atom.rules[r]){
    
77                     // look for + and * operators on atoms
    
78                     ratom = atom.rules[r][x];
    
79                     firstchar = ratom[0];
    
80                     if(firstchar == "+" || firstchar == "*"){
    
81                         ratom = ratom.slice(1);
    
82                     }
    
83                     else{
    
84                         firstchar = "";
    
85                     }
    
86                     atom.rules[r][x] = {
    
87                         "name": ratom,
    
88                         "operator":firstchar
    
89                     }
    
90                 }
    
91             }
    
92         }
    
93     }
    
94 
    95 
    96     // now go through again and make predictions
    
97     for(var g in grammar){ 
    
98         atom = grammar[g];
    
99 
   100         if(atom.rules){
   
101             atom.predictions = [];
   
102             for(r in atom.rules){
   
103                 atom.predictions.push(getprediction(atom.rules[r][0].name));
   
104             }
   
105         }
   
106     }
   
107 
   108     function getprediction(atom){
   
109         if(!grammar[atom]){ alert("Bad Grammar!  Couldn't find '"+atom+"'."); }
   
110         if(grammar[atom].rules){
   
111             return getprediction(grammar[atom].rules[0][0].name);
   
112         }
   
113         return grammar[atom].lookahead;
   
114     }
   
115 
   116 
   117 
   118 
   119     return grammar;
   
120 }