/[svn]/linuxsampler/trunk/src/network/lscp.y
ViewVC logotype

Diff of /linuxsampler/trunk/src/network/lscp.y

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 141 by senkov, Mon Jun 21 01:21:33 2004 UTC revision 2523 by schoenebeck, Sun Feb 23 19:10:36 2014 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6     *   Copyright (C) 2005 - 2014 Christian Schoenebeck                       *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
9   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 20  Line 21 
21   *   MA  02111-1307  USA                                                   *   *   MA  02111-1307  USA                                                   *
22   ***************************************************************************/   ***************************************************************************/
23    
24    /*
25        The parser's C++ source files should be automatically (re)generated if
26        this file was modified. If not, or in case you want explicitly
27        regenerate the parser C++ files, run 'make parser'. In both cases you
28        need to have bison or another yacc compatible parser generator
29        installed though.
30    */
31    
32  %{  %{
33    
34  #include "lscpparser.h"  #include "lscpparser.h"
35  #include "lscpserver.h"  #include "lscpserver.h"
36    #include "lscpevent.h"
37    #include "lscpsymbols.h"
38    #include <algorithm>
39    #include "lscp.h"
40    
41  // as we need an reentrant scanner, we have to pass the pointer to the scanner with each yylex() call  namespace LinuxSampler {
 #define YYLEX_PARAM ((yyparse_param_t*) yyparse_param)->pScanner  
42    
43  // to save us typing work in the rules action definitions  // to save us typing work in the rules action definitions
44  #define LSCPSERVER ((yyparse_param_t*) yyparse_param)->pServer  #define LSCPSERVER ((yyparse_param_t*) yyparse_param)->pServer
45    #define SESSION_PARAM ((yyparse_param_t*) yyparse_param)
46    #define INCREMENT_LINE { SESSION_PARAM->iLine++; SESSION_PARAM->iColumn = 0; sParsed.clear(); }
47    
48  // clears input buffer and restarts scanner.  // clears input buffer
49  void restart(yyparse_param_t* pparam, int& yychar);  void restart(yyparse_param_t* pparam, int& yychar);
50  #define RESTART restart((yyparse_param_t*) YYPARSE_PARAM, yychar)  #define RESTART restart((yyparse_param_t*) YYPARSE_PARAM, yychar)
51    
52  // external reference to the main scanner function yylex()  static char buf[1024]; // input buffer to feed the parser with new characters
53  extern YY_DECL;  static int bytes = 0;  // current number of characters in the input buffer
54    static int ptr   = 0;  // current position in the input buffer
55    static String sLastError; // error message of the last error occured
56    static String sParsed; ///< Characters of current line which have already been shifted (consumed/parsed) by the parser.
57    
58    // external reference to the function which actually reads from the socket
59    extern int GetLSCPCommand( void *buf, int max_size);
60    
61    // external reference to the function in lscpserver.cpp which returns the
62    // current session (only works because the server runs as singleton)
63    extern yyparse_param_t* GetCurrentYaccSession();
64    
65    // returns true if supplied characters has an ASCII code of 128 or higher
66    inline bool isExtendedAsciiChar(const char c) {
67        return (c < 0);
68    }
69    
70    // returns true if the given character is between between a to z.
71    inline bool isLowerCaseAlphaChar(const char c) {
72        return c >= 'a' && c <= 'z';
73    }
74    
75    // converts the given (expected) lower case character to upper case
76    inline char alphaCharToUpperCase(const char c) {
77        return (c - 'a') + 'A';
78    }
79    
80    // custom scanner function which reads from the socket
81    // (bison expects it to return the numerical ID of the next
82    // "recognized token" from the input stream)
83    int yylex(YYSTYPE* yylval) {
84        // check if we have to read new characters
85        if (ptr >= bytes) {
86            bytes = GetLSCPCommand(buf, 1023);
87            ptr   = 0;
88            if (bytes < 0) {
89                bytes = 0;
90                return 0;
91            }
92        }
93        // this is the next character in the input stream
94        const char c = buf[ptr++];
95        // increment current reading position (just for verbosity / messages)
96        GetCurrentYaccSession()->iColumn++;
97        sParsed += c;
98        // we have to handle "normal" and "extended" ASCII characters separately
99        if (isExtendedAsciiChar(c)) {
100            // workaround for characters with ASCII code higher than 127
101            yylval->Char = c;
102            return EXT_ASCII_CHAR;
103        } else {
104            // simply return the ASCII code as terminal symbol ID
105            return (int) c;
106        }
107    }
108    
109    // parser helper functions
110    
111    int octalsToNumber(char oct_digit0, char oct_digit1 = '0', char oct_digit2 = '0') {
112        const char d0[] = { oct_digit0, '\0' };
113        const char d1[] = { oct_digit1, '\0' };
114        const char d2[] = { oct_digit2, '\0' };
115        return atoi(d2)*8*8 + atoi(d1)*8 + atoi(d0);
116    }
117    
118    }
119    
120  // external reference to restart the lex scanner  using namespace LinuxSampler;
 extern void yyrestart(FILE* input_file, yyscan_t yyscanner);  
121    
122  // we provide our own version of yyerror() so we don't have to link against the yacc library  static std::set<String> yyExpectedSymbols();
123  void yyerror(const char* s);  
124    /**
125     * Will be called when an error occured (usually syntax error).
126     *
127     * We provide our own version of yyerror() so we a) don't have to link against
128     * the yacc library and b) can render more helpful syntax error messages.
129     */
130    void yyerror(void* x, const char* s) {
131        yyparse_param_t* param = GetCurrentYaccSession();
132    
133        // get the text part already parsed (of current line)
134        const bool bContainsLineFeed =
135            sParsed.find('\r') != std::string::npos ||
136            sParsed.find('\n') != std::string::npos;
137        // remove potential line feed characters
138        if (bContainsLineFeed) {
139            for (size_t p = sParsed.find('\r'); p != std::string::npos;
140                 p = sParsed.find('\r')) sParsed.erase(p);
141            for (size_t p = sParsed.find('\n'); p != std::string::npos;
142                 p = sParsed.find('\n')) sParsed.erase(p);
143        }
144    
145        // start assembling the error message with Bison's own message
146        String txt = s;
147    
148        // append exact position info of syntax error
149        txt += (" (line:"  + ToString(param->iLine+1)) +
150               (",column:" + ToString(param->iColumn)) + ")";
151    
152        // append the part of the lined that has already been parsed
153        txt += ". Context: \"" + sParsed;
154        if (txt.empty() || bContainsLineFeed)
155            txt += "^";
156        else
157            txt.insert(txt.size() - 1, "^");
158        txt += "...\"";
159    
160        // append the non-terminal symbols expected now/next
161        std::set<String> expectedSymbols = yyExpectedSymbols();
162        for (std::set<String>::const_iterator it = expectedSymbols.begin();
163             it != expectedSymbols.end(); ++it)
164        {
165            if (it == expectedSymbols.begin())
166                txt += " -> Should be: " + *it;
167            else
168                txt += " | " + *it;
169        }
170    
171        dmsg(2,("LSCPParser: %s\n", txt.c_str()));
172        sLastError = txt;
173    }
174    
175  %}  %}
176    
177  // reentrant parser  // reentrant parser
178  %pure_parser  %pure-parser
179    
180    %parse-param {void* yyparse_param}
181    
182    // After entering the yyparse() function, store references to the parser's
183    // state stack, so that we can create more helpful syntax error messages than
184    // Bison (2.x) could do.
185    %initial-action {
186        yyparse_param_t* p = (yyparse_param_t*) yyparse_param;
187        p->ppStackBottom = &yyss;
188        p->ppStackTop    = &yyssp;
189    }
190    
191    // tell bison to spit out verbose syntax error messages
192    %error-verbose
193    
194    %token <Char> EXT_ASCII_CHAR
195    
196  %token <Char>   CHAR  %type <Char> char char_base alpha_char digit digit_oct digit_hex escape_seq escape_seq_octal escape_seq_hex
197  %token <Dotnum> DOTNUM  %type <Dotnum> real dotnum volume_value boolean control_value
198  %token <Number> NUMBER  %type <Number> number sampler_channel instrument_index fx_send_id audio_channel_index device_index effect_index effect_instance effect_chain chain_pos input_control midi_input_channel_index midi_input_port_index midi_map midi_bank midi_prog midi_ctrl
199  %token <String> STRINGVAL  %type <String> string string_escaped text text_escaped text_escaped_base stringval stringval_escaped digits param_val_list param_val query_val filename module effect_system db_path map_name entry_name fx_send_name effect_name engine_name line statement command add_instruction create_instruction destroy_instruction get_instruction list_instruction load_instruction send_instruction set_chan_instruction load_instr_args load_engine_args audio_output_type_name midi_input_type_name remove_instruction unmap_instruction set_instruction subscribe_event unsubscribe_event map_instruction reset_instruction clear_instruction find_instruction move_instruction copy_instruction scan_mode edit_instruction format_instruction append_instruction insert_instruction
 %token SP LF CR HASH EQ  
 %token ADD GET CREATE DESTROY LIST LOAD NON_MODAL REMOVE SET SUBSCRIBE UNSUBSCRIBE RESET QUIT  
 %token CHANNEL NOTIFICATION  
 %token AVAILABLE_ENGINES AVAILABLE_AUDIO_OUTPUT_DRIVERS CHANNELS INFO BUFFER_FILL STREAM_COUNT VOICE_COUNT  
 %token INSTRUMENT ENGINE  
 %token AUDIO_OUTPUT_CHANNEL AUDIO_OUTPUT_CHANNEL_PARAMETER AUDIO_OUTPUT_DEVICE AUDIO_OUTPUT_DEVICES AUDIO_OUTPUT_DEVICE_PARAMETER AUDIO_OUTPUT_DRIVER AUDIO_OUTPUT_DRIVER_PARAMETER MIDI_INPUT_PORT MIDI_INPUT_CHANNEL MIDI_INPUT_TYPE VOLUME  
 %token BYTES PERCENTAGE  
 %token MISCELLANEOUS  
   
 %type <Dotnum> volume  
 %type <Number> sampler_channel instrument_index audio_output_channel midi_input_channel  
 %type <String> string param_val filename engine_name midi_input_port command create_instruction destroy_instruction get_instruction list_instruction load_instruction set_chan_instruction load_instr_args load_engine_args midi_input_type set_instruction subscribe_event unsubscribe_event  
200  %type <FillResponse> buffer_size_type  %type <FillResponse> buffer_size_type
201  %type <KeyValList> key_val_list  %type <KeyValList> key_val_list query_val_list
202    %type <LoadMode> instr_load_mode
203    %type <Bool> modal_arg
204    %type <UniversalPath> path path_base path_prefix path_body
205    
206  %start input  %start input
207    
# Line 74  void yyerror(const char* s); Line 209  void yyerror(const char* s);
209    
210  //TODO: return more meaningful error messages  //TODO: return more meaningful error messages
211    
212  input                 :  line  /*
213                        |  input LF line    The LSCP specification document input file (Documentation/lscp.xml) is
214                        |  input CR LF line    automatically updated with this file using the scripts/update_grammar.pl
215      script. Do not modify or delete the GRAMMAR_BNF_BEGIN and GRAMMAR_BNF_END
216      lines !
217    */
218    
219    // GRAMMAR_BNF_BEGIN - do NOT delete or modify this line !!!
220    
221    input                 :  line   { INCREMENT_LINE; if (!$1.empty()) LSCPSERVER->AnswerClient($1); return LSCP_DONE; }
222                          |  error  { INCREMENT_LINE; LSCPSERVER->AnswerClient("ERR:0:" + sLastError + "\r\n"); RESTART; return LSCP_SYNTAX_ERROR; }
223                          ;
224    
225    line                  :  statement LF     { $$ = $1; }
226                          |  statement CR LF  { $$ = $1; }
227                        ;                        ;
228    
229  line                  :  /* epsilon (empty line ignored) */  statement             :  /* epsilon (empty statement/line ignored) */  { $$ = ""; }
230                        |  comment                        |  comment  { $$ = ""; }
231                        |  command  { LSCPSERVER->AnswerClient($1); }                        |  command
                       |  error    { LSCPSERVER->AnswerClient("Err:0:Unknown command.\r\n"); RESTART; return LSCP_SYNTAX_ERROR; }  
232                        ;                        ;
233    
234  comment               :  HASH  comment               :  '#'
235                        |  comment HASH                        |  comment '#'
236                        |  comment SP                        |  comment SP
237                        |  comment NUMBER                        |  comment number
238                        |  comment string                        |  comment string
239                        ;                        ;
240    
241  command               :  ADD SP CHANNEL                             { $$ = LSCPSERVER->AddChannel();                  }  command               :  ADD SP add_instruction                { $$ = $3;                                                }
242                        |  GET SP get_instruction                     { $$ = $3;                                        }                        |  MAP SP map_instruction                { $$ = $3;                                                }
243                        |  CREATE SP create_instruction               { $$ = $3;                                        }                        |  UNMAP SP unmap_instruction            { $$ = $3;                                                }
244                        |  DESTROY SP destroy_instruction             { $$ = $3;                                        }                        |  GET SP get_instruction                { $$ = $3;                                                }
245                        |  LIST SP list_instruction                   { $$ = $3;                                        }                        |  CREATE SP create_instruction          { $$ = $3;                                                }
246                        |  LOAD SP load_instruction                   { $$ = $3;                                        }                        |  DESTROY SP destroy_instruction        { $$ = $3;                                                }
247                        |  REMOVE SP CHANNEL SP sampler_channel       { $$ = LSCPSERVER->RemoveChannel($5);             }                        |  LIST SP list_instruction              { $$ = $3;                                                }
248                        |  SET SP set_instruction                     { $$ = $3;                                        }                        |  LOAD SP load_instruction              { $$ = $3;                                                }
249                        |  SUBSCRIBE SP subscribe_event               { $$ = $3;                                        }                        |  REMOVE SP remove_instruction          { $$ = $3;                                                }
250                        |  UNSUBSCRIBE SP unsubscribe_event           { $$ = $3;                                        }                        |  SET SP set_instruction                { $$ = $3;                                                }
251                        |  RESET SP CHANNEL SP sampler_channel        { $$ = LSCPSERVER->ResetChannel($5);              }                        |  SUBSCRIBE SP subscribe_event          { $$ = $3;                                                }
252                        |  QUIT                                       { LSCPSERVER->AnswerClient("Bye!\r\n"); return 0; }                        |  UNSUBSCRIBE SP unsubscribe_event      { $$ = $3;                                                }
253                        ;                        |  RESET SP reset_instruction            { $$ = $3;                                                }
254                          |  CLEAR SP clear_instruction            { $$ = $3;                                                }
255  subscribe_event       :  CHANNELS                                   { $$ = LSCPSERVER->SubscribeNotification(event_channels); }                        |  FIND SP find_instruction              { $$ = $3;                                                }
256                        |  VOICE_COUNT                                { $$ = LSCPSERVER->SubscribeNotification(event_voice_count); }                        |  MOVE SP move_instruction              { $$ = $3;                                                }
257                        |  STREAM_COUNT                               { $$ = LSCPSERVER->SubscribeNotification(event_stream_count); }                        |  COPY SP copy_instruction              { $$ = $3;                                                }
258                        |  BUFFER_FILL                                { $$ = LSCPSERVER->SubscribeNotification(event_channel_buffer_fill); }                        |  EDIT SP edit_instruction              { $$ = $3;                                                }
259                        |  INFO                                       { $$ = LSCPSERVER->SubscribeNotification(event_channel_info); }                        |  FORMAT SP format_instruction          { $$ = $3;                                                }
260                        |  MISCELLANEOUS                              { $$ = LSCPSERVER->SubscribeNotification(event_misc); }                        |  SEND SP send_instruction              { $$ = $3;                                                }
261                        ;                        |  APPEND SP append_instruction          { $$ = $3;                                                }
262                          |  INSERT SP insert_instruction          { $$ = $3;                                                }
263  unsubscribe_event     :  CHANNELS                                   { $$ = LSCPSERVER->UnsubscribeNotification(event_channels); }                        |  RESET                                 { $$ = LSCPSERVER->ResetSampler();                        }
264                        |  VOICE_COUNT                                { $$ = LSCPSERVER->UnsubscribeNotification(event_voice_count); }                        |  QUIT                                  { LSCPSERVER->AnswerClient("Bye!\r\n"); return LSCP_QUIT; }
265                        |  STREAM_COUNT                               { $$ = LSCPSERVER->UnsubscribeNotification(event_stream_count); }                        ;
266                        |  BUFFER_FILL                                { $$ = LSCPSERVER->UnsubscribeNotification(event_channel_buffer_fill); }  
267                        |  INFO                                       { $$ = LSCPSERVER->UnsubscribeNotification(event_channel_info); }  add_instruction       :  CHANNEL                               { $$ = LSCPSERVER->AddChannel();                  }
268                        |  MISCELLANEOUS                              { $$ = LSCPSERVER->UnsubscribeNotification(event_misc); }                        |  CHANNEL SP MIDI_INPUT SP sampler_channel SP device_index                           { $$ = LSCPSERVER->AddChannelMidiInput($5,$7);    }
269                          |  CHANNEL SP MIDI_INPUT SP sampler_channel SP device_index SP midi_input_port_index  { $$ = LSCPSERVER->AddChannelMidiInput($5,$7,$9); }
270                          |  DB_INSTRUMENT_DIRECTORY SP db_path    { $$ = LSCPSERVER->AddDbInstrumentDirectory($3);  }
271                          |  DB_INSTRUMENTS SP NON_MODAL SP scan_mode SP db_path SP filename                        { $$ = LSCPSERVER->AddDbInstruments($5,$7,$9, true);        }
272                          |  DB_INSTRUMENTS SP NON_MODAL SP scan_mode SP FILE_AS_DIR SP db_path SP filename         { $$ = LSCPSERVER->AddDbInstruments($5,$9,$11, true, true); }
273                          |  DB_INSTRUMENTS SP scan_mode SP db_path SP filename                                     { $$ = LSCPSERVER->AddDbInstruments($3,$5,$7);              }
274                          |  DB_INSTRUMENTS SP scan_mode SP FILE_AS_DIR SP db_path SP filename                      { $$ = LSCPSERVER->AddDbInstruments($3,$7,$9, false, true); }
275                          |  DB_INSTRUMENTS SP NON_MODAL SP db_path SP filename                                     { $$ = LSCPSERVER->AddDbInstruments($5,$7, -1, true);       }
276                          |  DB_INSTRUMENTS SP NON_MODAL SP db_path SP filename SP instrument_index                 { $$ = LSCPSERVER->AddDbInstruments($5,$7,$9, true);        }
277                          |  DB_INSTRUMENTS SP db_path SP filename                                                  { $$ = LSCPSERVER->AddDbInstruments($3,$5);                 }
278                          |  DB_INSTRUMENTS SP db_path SP filename SP instrument_index                              { $$ = LSCPSERVER->AddDbInstruments($3,$5,$7);              }
279                          |  MIDI_INSTRUMENT_MAP                   { $$ = LSCPSERVER->AddMidiInstrumentMap();                }
280                          |  MIDI_INSTRUMENT_MAP SP map_name       { $$ = LSCPSERVER->AddMidiInstrumentMap($3);              }
281                          |  SEND_EFFECT_CHAIN SP device_index     { $$ = LSCPSERVER->AddSendEffectChain($3);                }
282                          ;
283    
284    subscribe_event       :  AUDIO_OUTPUT_DEVICE_COUNT             { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_audio_device_count);   }
285                          |  AUDIO_OUTPUT_DEVICE_INFO              { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_audio_device_info);    }
286                          |  MIDI_INPUT_DEVICE_COUNT               { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_midi_device_count);    }
287                          |  MIDI_INPUT_DEVICE_INFO                { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_midi_device_info);     }
288                          |  CHANNEL_COUNT                         { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_channel_count);        }
289                          |  CHANNEL_MIDI                          { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_channel_midi);         }
290                          |  DEVICE_MIDI                           { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_device_midi);          }
291                          |  VOICE_COUNT                           { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_voice_count);          }
292                          |  STREAM_COUNT                          { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_stream_count);         }
293                          |  BUFFER_FILL                           { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_buffer_fill);          }
294                          |  CHANNEL_INFO                          { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_channel_info);         }
295                          |  FX_SEND_COUNT                         { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_fx_send_count);        }
296                          |  FX_SEND_INFO                          { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_fx_send_info);         }
297                          |  MIDI_INSTRUMENT_MAP_COUNT             { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_midi_instr_map_count); }
298                          |  MIDI_INSTRUMENT_MAP_INFO              { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_midi_instr_map_info);  }
299                          |  MIDI_INSTRUMENT_COUNT                 { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_midi_instr_count);     }
300                          |  MIDI_INSTRUMENT_INFO                  { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_midi_instr_info);      }
301                          |  DB_INSTRUMENT_DIRECTORY_COUNT         { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_db_instr_dir_count);   }
302                          |  DB_INSTRUMENT_DIRECTORY_INFO          { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_db_instr_dir_info);    }
303                          |  DB_INSTRUMENT_COUNT                   { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_db_instr_count);       }
304                          |  DB_INSTRUMENT_INFO                    { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_db_instr_info);        }
305                          |  DB_INSTRUMENTS_JOB_INFO               { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_db_instrs_job_info);   }
306                          |  MISCELLANEOUS                         { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_misc);                 }
307                          |  TOTAL_STREAM_COUNT                    { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_total_stream_count);   }
308                          |  TOTAL_VOICE_COUNT                     { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_total_voice_count);    }
309                          |  GLOBAL_INFO                           { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_global_info);          }
310                          |  EFFECT_INSTANCE_COUNT                 { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_fx_instance_count);    }
311                          |  EFFECT_INSTANCE_INFO                  { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_fx_instance_info);     }
312                          |  SEND_EFFECT_CHAIN_COUNT               { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_send_fx_chain_count);  }
313                          |  SEND_EFFECT_CHAIN_INFO                { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_send_fx_chain_info);   }
314                          ;
315    
316    unsubscribe_event     :  AUDIO_OUTPUT_DEVICE_COUNT             { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_audio_device_count);   }
317                          |  AUDIO_OUTPUT_DEVICE_INFO              { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_audio_device_info);    }
318                          |  MIDI_INPUT_DEVICE_COUNT               { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_midi_device_count);    }
319                          |  MIDI_INPUT_DEVICE_INFO                { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_midi_device_info);     }
320                          |  CHANNEL_COUNT                         { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_channel_count);        }
321                          |  CHANNEL_MIDI                          { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_channel_midi);         }
322                          |  DEVICE_MIDI                           { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_device_midi);          }
323                          |  VOICE_COUNT                           { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_voice_count);          }
324                          |  STREAM_COUNT                          { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_stream_count);         }
325                          |  BUFFER_FILL                           { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_buffer_fill);          }
326                          |  CHANNEL_INFO                          { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_channel_info);         }
327                          |  FX_SEND_COUNT                         { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_fx_send_count);        }
328                          |  FX_SEND_INFO                          { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_fx_send_info);         }
329                          |  MIDI_INSTRUMENT_MAP_COUNT             { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_midi_instr_map_count); }
330                          |  MIDI_INSTRUMENT_MAP_INFO              { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_midi_instr_map_info);  }
331                          |  MIDI_INSTRUMENT_COUNT                 { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_midi_instr_count);     }
332                          |  MIDI_INSTRUMENT_INFO                  { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_midi_instr_info);      }
333                          |  DB_INSTRUMENT_DIRECTORY_COUNT         { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_db_instr_dir_count);   }
334                          |  DB_INSTRUMENT_DIRECTORY_INFO          { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_db_instr_dir_info);    }
335                          |  DB_INSTRUMENT_COUNT                   { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_db_instr_count);       }
336                          |  DB_INSTRUMENT_INFO                    { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_db_instr_info);        }
337                          |  DB_INSTRUMENTS_JOB_INFO               { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_db_instrs_job_info);   }
338                          |  MISCELLANEOUS                         { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_misc);                 }
339                          |  TOTAL_STREAM_COUNT                    { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_total_stream_count);   }
340                          |  TOTAL_VOICE_COUNT                     { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_total_voice_count);    }
341                          |  GLOBAL_INFO                           { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_global_info);          }
342                          |  EFFECT_INSTANCE_COUNT                 { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_fx_instance_count);    }
343                          |  EFFECT_INSTANCE_INFO                  { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_fx_instance_info);     }
344                          |  SEND_EFFECT_CHAIN_COUNT               { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_send_fx_chain_count);  }
345                          |  SEND_EFFECT_CHAIN_INFO                { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_send_fx_chain_info);   }
346                          ;
347    
348    map_instruction       :  MIDI_INSTRUMENT SP modal_arg midi_map SP midi_bank SP midi_prog SP engine_name SP filename SP instrument_index SP volume_value { $$ = LSCPSERVER->AddOrReplaceMIDIInstrumentMapping($4,$6,$8,$10,$12,$14,$16,MidiInstrumentMapper::DONTCARE,"",$3); }
349                          |  MIDI_INSTRUMENT SP modal_arg midi_map SP midi_bank SP midi_prog SP engine_name SP filename SP instrument_index SP volume_value SP instr_load_mode { $$ = LSCPSERVER->AddOrReplaceMIDIInstrumentMapping($4,$6,$8,$10,$12,$14,$16,$18,"",$3); }
350                          |  MIDI_INSTRUMENT SP modal_arg midi_map SP midi_bank SP midi_prog SP engine_name SP filename SP instrument_index SP volume_value SP entry_name { $$ = LSCPSERVER->AddOrReplaceMIDIInstrumentMapping($4,$6,$8,$10,$12,$14,$16,MidiInstrumentMapper::DONTCARE,$18,$3); }
351                          |  MIDI_INSTRUMENT SP modal_arg midi_map SP midi_bank SP midi_prog SP engine_name SP filename SP instrument_index SP volume_value SP instr_load_mode SP entry_name { $$ = LSCPSERVER->AddOrReplaceMIDIInstrumentMapping($4,$6,$8,$10,$12,$14,$16,$18,$20,$3); }
352                          ;
353    
354    unmap_instruction     :  MIDI_INSTRUMENT SP midi_map SP midi_bank SP midi_prog  { $$ = LSCPSERVER->RemoveMIDIInstrumentMapping($3,$5,$7); }
355                          ;
356    
357    remove_instruction    :  CHANNEL SP sampler_channel                   { $$ = LSCPSERVER->RemoveChannel($3);                      }
358                          |  CHANNEL SP MIDI_INPUT SP sampler_channel                                           { $$ = LSCPSERVER->RemoveChannelMidiInput($5);       }
359                          |  CHANNEL SP MIDI_INPUT SP sampler_channel SP device_index                           { $$ = LSCPSERVER->RemoveChannelMidiInput($5,$7);    }
360                          |  CHANNEL SP MIDI_INPUT SP sampler_channel SP device_index SP midi_input_port_index  { $$ = LSCPSERVER->RemoveChannelMidiInput($5,$7,$9); }
361                          |  MIDI_INSTRUMENT_MAP SP midi_map              { $$ = LSCPSERVER->RemoveMidiInstrumentMap($3);            }
362                          |  MIDI_INSTRUMENT_MAP SP ALL                   { $$ = LSCPSERVER->RemoveAllMidiInstrumentMaps();          }
363                          |  SEND_EFFECT_CHAIN SP device_index SP effect_chain  { $$ = LSCPSERVER->RemoveSendEffectChain($3,$5);     }
364                          |  SEND_EFFECT_CHAIN SP EFFECT SP device_index SP effect_chain SP chain_pos  { $$ = LSCPSERVER->RemoveSendEffectChainEffect($5,$7,$9); }
365                          |  FX_SEND SP EFFECT SP sampler_channel SP fx_send_id  { $$ = LSCPSERVER->SetFxSendEffect($5,$7,-1,-1);    }
366                          |  DB_INSTRUMENT_DIRECTORY SP FORCE SP db_path  { $$ = LSCPSERVER->RemoveDbInstrumentDirectory($5, true);  }
367                          |  DB_INSTRUMENT_DIRECTORY SP db_path           { $$ = LSCPSERVER->RemoveDbInstrumentDirectory($3);        }
368                          |  DB_INSTRUMENT SP db_path                     { $$ = LSCPSERVER->RemoveDbInstrument($3);                 }
369                        ;                        ;
370    
371  get_instruction       :  AVAILABLE_ENGINES                                                          { $$ = LSCPSERVER->GetAvailableEngines();                          }  get_instruction       :  AVAILABLE_ENGINES                                                          { $$ = LSCPSERVER->GetAvailableEngines();                          }
372                          |  AVAILABLE_EFFECTS                                                          { $$ = LSCPSERVER->GetAvailableEffects();                          }
373                          |  EFFECT_INSTANCES                                                           { $$ = LSCPSERVER->GetEffectInstances();                           }
374                          |  EFFECT SP INFO SP effect_index                                             { $$ = LSCPSERVER->GetEffectInfo($5);                              }
375                          |  EFFECT_INSTANCE SP INFO SP effect_instance                                 { $$ = LSCPSERVER->GetEffectInstanceInfo($5);                      }
376                          |  EFFECT_INSTANCE_INPUT_CONTROL SP INFO SP effect_instance SP input_control  { $$ = LSCPSERVER->GetEffectInstanceInputControlInfo($5,$7);       }
377                          |  SEND_EFFECT_CHAINS SP device_index                                         { $$ = LSCPSERVER->GetSendEffectChains($3);                        }
378                          |  SEND_EFFECT_CHAIN SP INFO SP device_index SP effect_chain                  { $$ = LSCPSERVER->GetSendEffectChainInfo($5,$7);                  }
379                          |  AVAILABLE_MIDI_INPUT_DRIVERS                                               { $$ = LSCPSERVER->GetAvailableMidiInputDrivers();                 }
380                          |  MIDI_INPUT_DRIVER SP INFO SP string                                        { $$ = LSCPSERVER->GetMidiInputDriverInfo($5);                     }
381                          |  MIDI_INPUT_DRIVER_PARAMETER SP INFO SP string SP string                    { $$ = LSCPSERVER->GetMidiInputDriverParameterInfo($5, $7);        }
382                          |  MIDI_INPUT_DRIVER_PARAMETER SP INFO SP string SP string SP key_val_list    { $$ = LSCPSERVER->GetMidiInputDriverParameterInfo($5, $7, $9);    }
383                        |  AVAILABLE_AUDIO_OUTPUT_DRIVERS                                             { $$ = LSCPSERVER->GetAvailableAudioOutputDrivers();               }                        |  AVAILABLE_AUDIO_OUTPUT_DRIVERS                                             { $$ = LSCPSERVER->GetAvailableAudioOutputDrivers();               }
384                        |  AUDIO_OUTPUT_DRIVER SP INFO SP string                                      { $$ = LSCPSERVER->GetAudioOutputDriverInfo($5);                   }                        |  AUDIO_OUTPUT_DRIVER SP INFO SP string                                      { $$ = LSCPSERVER->GetAudioOutputDriverInfo($5);                   }
385                        |  AUDIO_OUTPUT_DRIVER_PARAMETER SP INFO SP string SP string                  { $$ = LSCPSERVER->GetAudioOutputDriverParameterInfo($5, $7);      }                        |  AUDIO_OUTPUT_DRIVER_PARAMETER SP INFO SP string SP string                  { $$ = LSCPSERVER->GetAudioOutputDriverParameterInfo($5, $7);      }
386                        |  AUDIO_OUTPUT_DRIVER_PARAMETER SP INFO SP string SP string SP key_val_list  { $$ = LSCPSERVER->GetAudioOutputDriverParameterInfo($5, $7, $9);  }                        |  AUDIO_OUTPUT_DRIVER_PARAMETER SP INFO SP string SP string SP key_val_list  { $$ = LSCPSERVER->GetAudioOutputDriverParameterInfo($5, $7, $9);  }
387                        |  AUDIO_OUTPUT_DEVICES                                                       { $$ = LSCPSERVER->GetAudioOutputDeviceCount();                    }                        |  AUDIO_OUTPUT_DEVICES                                                       { $$ = LSCPSERVER->GetAudioOutputDeviceCount();                    }
388                        |  AUDIO_OUTPUT_DEVICE SP INFO SP NUMBER                                      { $$ = LSCPSERVER->GetAudioOutputDeviceInfo($5);                   }                        |  MIDI_INPUT_DEVICES                                                         { $$ = LSCPSERVER->GetMidiInputDeviceCount();                      }
389                        |  AUDIO_OUTPUT_CHANNEL SP INFO SP NUMBER SP NUMBER                           { $$ = LSCPSERVER->GetAudioOutputChannelInfo($5, $7);              }                        |  AUDIO_OUTPUT_DEVICE SP INFO SP number                                      { $$ = LSCPSERVER->GetAudioOutputDeviceInfo($5);                   }
390                        |  AUDIO_OUTPUT_CHANNEL_PARAMETER SP INFO SP NUMBER SP NUMBER SP string       { $$ = LSCPSERVER->GetAudioOutputChannelParameterInfo($5, $7, $9); }                        |  MIDI_INPUT_DEVICE SP INFO SP number                                        { $$ = LSCPSERVER->GetMidiInputDeviceInfo($5);                     }
391                          |  MIDI_INPUT_PORT SP INFO SP number SP number                                { $$ = LSCPSERVER->GetMidiInputPortInfo($5, $7);                   }
392                          |  MIDI_INPUT_PORT_PARAMETER SP INFO SP number SP number SP string            { $$ = LSCPSERVER->GetMidiInputPortParameterInfo($5, $7, $9);      }
393                          |  AUDIO_OUTPUT_CHANNEL SP INFO SP number SP number                           { $$ = LSCPSERVER->GetAudioOutputChannelInfo($5, $7);              }
394                          |  AUDIO_OUTPUT_CHANNEL_PARAMETER SP INFO SP number SP number SP string       { $$ = LSCPSERVER->GetAudioOutputChannelParameterInfo($5, $7, $9); }
395                        |  CHANNELS                                                                   { $$ = LSCPSERVER->GetChannels();                                  }                        |  CHANNELS                                                                   { $$ = LSCPSERVER->GetChannels();                                  }
396                        |  CHANNEL SP INFO SP sampler_channel                                         { $$ = LSCPSERVER->GetChannelInfo($5);                             }                        |  CHANNEL SP INFO SP sampler_channel                                         { $$ = LSCPSERVER->GetChannelInfo($5);                             }
397                        |  CHANNEL SP BUFFER_FILL SP buffer_size_type SP sampler_channel              { $$ = LSCPSERVER->GetBufferFill($5, $7);                          }                        |  CHANNEL SP BUFFER_FILL SP buffer_size_type SP sampler_channel              { $$ = LSCPSERVER->GetBufferFill($5, $7);                          }
398                        |  CHANNEL SP STREAM_COUNT SP sampler_channel                                 { $$ = LSCPSERVER->GetStreamCount($5);                             }                        |  CHANNEL SP STREAM_COUNT SP sampler_channel                                 { $$ = LSCPSERVER->GetStreamCount($5);                             }
399                        |  CHANNEL SP VOICE_COUNT SP sampler_channel                                  { $$ = LSCPSERVER->GetVoiceCount($5);                              }                        |  CHANNEL SP VOICE_COUNT SP sampler_channel                                  { $$ = LSCPSERVER->GetVoiceCount($5);                              }
400                        |  ENGINE SP INFO SP engine_name                                              { $$ = LSCPSERVER->GetEngineInfo($5);                              }                        |  ENGINE SP INFO SP engine_name                                              { $$ = LSCPSERVER->GetEngineInfo($5);                              }
401                          |  SERVER SP INFO                                                             { $$ = LSCPSERVER->GetServerInfo();                                }
402                          |  TOTAL_STREAM_COUNT                                                         { $$ = LSCPSERVER->GetTotalStreamCount();                           }
403                          |  TOTAL_VOICE_COUNT                                                          { $$ = LSCPSERVER->GetTotalVoiceCount();                           }
404                          |  TOTAL_VOICE_COUNT_MAX                                                      { $$ = LSCPSERVER->GetTotalVoiceCountMax();                        }
405                          |  MIDI_INSTRUMENTS SP midi_map                                               { $$ = LSCPSERVER->GetMidiInstrumentMappings($3);                  }
406                          |  MIDI_INSTRUMENTS SP ALL                                                    { $$ = LSCPSERVER->GetAllMidiInstrumentMappings();                 }
407                          |  MIDI_INSTRUMENT SP INFO SP midi_map SP midi_bank SP midi_prog              { $$ = LSCPSERVER->GetMidiInstrumentMapping($5,$7,$9);             }
408                          |  MIDI_INSTRUMENT_MAPS                                                       { $$ = LSCPSERVER->GetMidiInstrumentMaps();                        }
409                          |  MIDI_INSTRUMENT_MAP SP INFO SP midi_map                                    { $$ = LSCPSERVER->GetMidiInstrumentMap($5);                       }
410                          |  FX_SENDS SP sampler_channel                                                { $$ = LSCPSERVER->GetFxSends($3);                                 }
411                          |  FX_SEND SP INFO SP sampler_channel SP fx_send_id                           { $$ = LSCPSERVER->GetFxSendInfo($5,$7);                           }
412                          |  DB_INSTRUMENT_DIRECTORIES SP RECURSIVE SP db_path                          { $$ = LSCPSERVER->GetDbInstrumentDirectoryCount($5, true);        }
413                          |  DB_INSTRUMENT_DIRECTORIES SP db_path                                       { $$ = LSCPSERVER->GetDbInstrumentDirectoryCount($3, false);       }
414                          |  DB_INSTRUMENT_DIRECTORY SP INFO SP db_path                                 { $$ = LSCPSERVER->GetDbInstrumentDirectoryInfo($5);               }
415                          |  DB_INSTRUMENTS SP RECURSIVE SP db_path                                     { $$ = LSCPSERVER->GetDbInstrumentCount($5, true);                 }
416                          |  DB_INSTRUMENTS SP db_path                                                  { $$ = LSCPSERVER->GetDbInstrumentCount($3, false);                }
417                          |  DB_INSTRUMENT SP INFO SP db_path                                           { $$ = LSCPSERVER->GetDbInstrumentInfo($5);                        }
418                          |  DB_INSTRUMENTS_JOB SP INFO SP number                                       { $$ = LSCPSERVER->GetDbInstrumentsJobInfo($5);                    }
419                          |  VOLUME                                                                     { $$ = LSCPSERVER->GetGlobalVolume();                              }
420                          |  VOICES                                                                     { $$ = LSCPSERVER->GetGlobalMaxVoices();                           }
421                          |  STREAMS                                                                    { $$ = LSCPSERVER->GetGlobalMaxStreams();                          }
422                          |  FILE SP INSTRUMENTS SP filename                                            { $$ = LSCPSERVER->GetFileInstruments($5);                         }
423                          |  FILE SP INSTRUMENT SP INFO SP filename SP instrument_index                 { $$ = LSCPSERVER->GetFileInstrumentInfo($7,$9);                   }
424                          ;
425    
426    set_instruction       :  AUDIO_OUTPUT_DEVICE_PARAMETER SP number SP string '=' param_val_list             { $$ = LSCPSERVER->SetAudioOutputDeviceParameter($3, $5, $7);      }
427                          |  AUDIO_OUTPUT_CHANNEL_PARAMETER SP number SP number SP string '=' param_val_list  { $$ = LSCPSERVER->SetAudioOutputChannelParameter($3, $5, $7, $9); }
428                          |  MIDI_INPUT_DEVICE_PARAMETER SP number SP string '=' param_val_list               { $$ = LSCPSERVER->SetMidiInputDeviceParameter($3, $5, $7);        }
429                          |  MIDI_INPUT_PORT_PARAMETER SP number SP number SP string '=' NONE                 { $$ = LSCPSERVER->SetMidiInputPortParameter($3, $5, $7, "");      }
430                          |  MIDI_INPUT_PORT_PARAMETER SP number SP number SP string '=' param_val_list       { $$ = LSCPSERVER->SetMidiInputPortParameter($3, $5, $7, $9);      }
431                          |  EFFECT_INSTANCE_INPUT_CONTROL SP VALUE SP effect_instance SP input_control SP control_value  { $$ = LSCPSERVER->SetEffectInstanceInputControlValue($5, $7, $9); }
432                          |  CHANNEL SP set_chan_instruction                                                  { $$ = $3;                                                         }
433                          |  MIDI_INSTRUMENT_MAP SP NAME SP midi_map SP map_name                              { $$ = LSCPSERVER->SetMidiInstrumentMapName($5, $7);               }
434                          |  FX_SEND SP NAME SP sampler_channel SP fx_send_id SP fx_send_name                 { $$ = LSCPSERVER->SetFxSendName($5,$7,$9);                        }
435                          |  FX_SEND SP AUDIO_OUTPUT_CHANNEL SP sampler_channel SP fx_send_id SP audio_channel_index SP audio_channel_index  { $$ = LSCPSERVER->SetFxSendAudioOutputChannel($5,$7,$9,$11); }
436                          |  FX_SEND SP MIDI_CONTROLLER SP sampler_channel SP fx_send_id SP midi_ctrl         { $$ = LSCPSERVER->SetFxSendMidiController($5,$7,$9);              }
437                          |  FX_SEND SP LEVEL SP sampler_channel SP fx_send_id SP volume_value                { $$ = LSCPSERVER->SetFxSendLevel($5,$7,$9);                       }
438                          |  FX_SEND SP EFFECT SP sampler_channel SP fx_send_id SP effect_chain SP chain_pos  { $$ = LSCPSERVER->SetFxSendEffect($5,$7,$9,$11);                  }
439                          |  DB_INSTRUMENT_DIRECTORY SP NAME SP db_path SP stringval_escaped                  { $$ = LSCPSERVER->SetDbInstrumentDirectoryName($5,$7);            }
440                          |  DB_INSTRUMENT_DIRECTORY SP DESCRIPTION SP db_path SP stringval_escaped           { $$ = LSCPSERVER->SetDbInstrumentDirectoryDescription($5,$7);     }
441                          |  DB_INSTRUMENT SP NAME SP db_path SP stringval_escaped                            { $$ = LSCPSERVER->SetDbInstrumentName($5,$7);                     }
442                          |  DB_INSTRUMENT SP DESCRIPTION SP db_path SP stringval_escaped                     { $$ = LSCPSERVER->SetDbInstrumentDescription($5,$7);              }
443                          |  DB_INSTRUMENT SP FILE_PATH SP filename SP filename                               { $$ = LSCPSERVER->SetDbInstrumentFilePath($5,$7);                 }
444                          |  ECHO SP boolean                                                                  { $$ = LSCPSERVER->SetEcho((yyparse_param_t*) yyparse_param, $3);  }
445                          |  SHELL SP INTERACT SP boolean                                                     { $$ = LSCPSERVER->SetShellInteract((yyparse_param_t*) yyparse_param, $5); }
446                          |  SHELL SP AUTO_CORRECT SP boolean                                                 { $$ = LSCPSERVER->SetShellAutoCorrect((yyparse_param_t*) yyparse_param, $5); }
447                          |  VOLUME SP volume_value                                                           { $$ = LSCPSERVER->SetGlobalVolume($3);                            }
448                          |  VOICES SP number                                                                 { $$ = LSCPSERVER->SetGlobalMaxVoices($3);                         }
449                          |  STREAMS SP number                                                                { $$ = LSCPSERVER->SetGlobalMaxStreams($3);                        }
450                          ;
451    
452    create_instruction    :  AUDIO_OUTPUT_DEVICE SP string SP key_val_list  { $$ = LSCPSERVER->CreateAudioOutputDevice($3,$5); }
453                          |  AUDIO_OUTPUT_DEVICE SP string                  { $$ = LSCPSERVER->CreateAudioOutputDevice($3);    }
454                          |  MIDI_INPUT_DEVICE SP string SP key_val_list    { $$ = LSCPSERVER->CreateMidiInputDevice($3,$5);   }
455                          |  MIDI_INPUT_DEVICE SP string                    { $$ = LSCPSERVER->CreateMidiInputDevice($3);      }
456                          |  FX_SEND SP sampler_channel SP midi_ctrl        { $$ = LSCPSERVER->CreateFxSend($3,$5);            }
457                          |  FX_SEND SP sampler_channel SP midi_ctrl SP fx_send_name  { $$ = LSCPSERVER->CreateFxSend($3,$5,$7); }
458                          |  EFFECT_INSTANCE SP effect_index                { $$ = LSCPSERVER->CreateEffectInstance($3);       }
459                          |  EFFECT_INSTANCE SP effect_system SP module SP effect_name  { $$ = LSCPSERVER->CreateEffectInstance($3,$5,$7); }
460                          ;
461    
462    reset_instruction     :  CHANNEL SP sampler_channel  { $$ = LSCPSERVER->ResetChannel($3); }
463                          ;
464    
465    clear_instruction     :  MIDI_INSTRUMENTS SP midi_map   { $$ = LSCPSERVER->ClearMidiInstrumentMappings($3);  }
466                          |  MIDI_INSTRUMENTS SP ALL        { $$ = LSCPSERVER->ClearAllMidiInstrumentMappings(); }
467                          ;
468    
469    find_instruction      :  DB_INSTRUMENTS SP NON_RECURSIVE SP db_path SP query_val_list              { $$ = LSCPSERVER->FindDbInstruments($5,$7, false);           }
470                          |  DB_INSTRUMENTS SP db_path SP query_val_list                               { $$ = LSCPSERVER->FindDbInstruments($3,$5, true);            }
471                          |  DB_INSTRUMENT_DIRECTORIES SP NON_RECURSIVE SP db_path SP query_val_list   { $$ = LSCPSERVER->FindDbInstrumentDirectories($5,$7, false); }
472                          |  DB_INSTRUMENT_DIRECTORIES SP db_path SP query_val_list                    { $$ = LSCPSERVER->FindDbInstrumentDirectories($3,$5, true);  }
473                          |  LOST SP DB_INSTRUMENT_FILES                                               { $$ = LSCPSERVER->FindLostDbInstrumentFiles();                 }
474                          ;
475    
476    move_instruction      :  DB_INSTRUMENT_DIRECTORY SP db_path SP db_path    { $$ = LSCPSERVER->MoveDbInstrumentDirectory($3,$5); }
477                          |  DB_INSTRUMENT SP db_path SP db_path              { $$ = LSCPSERVER->MoveDbInstrument($3,$5);          }
478                          ;
479    
480    copy_instruction      :  DB_INSTRUMENT_DIRECTORY SP db_path SP db_path    { $$ = LSCPSERVER->CopyDbInstrumentDirectory($3,$5); }
481                          |  DB_INSTRUMENT SP db_path SP db_path              { $$ = LSCPSERVER->CopyDbInstrument($3,$5);          }
482                          ;
483    
484    destroy_instruction   :  AUDIO_OUTPUT_DEVICE SP number  { $$ = LSCPSERVER->DestroyAudioOutputDevice($3); }
485                          |  MIDI_INPUT_DEVICE SP number    { $$ = LSCPSERVER->DestroyMidiInputDevice($3);   }
486                          |  FX_SEND SP sampler_channel SP fx_send_id  { $$ = LSCPSERVER->DestroyFxSend($3,$5); }
487                          |  EFFECT_INSTANCE SP number      { $$ = LSCPSERVER->DestroyEffectInstance($3);    }
488                        ;                        ;
489    
490  set_instruction       :  AUDIO_OUTPUT_DEVICE_PARAMETER SP NUMBER SP string EQ param_val             { $$ = LSCPSERVER->SetAudioOutputDeviceParameter($3, $5, $7);      }  load_instruction      :  INSTRUMENT SP load_instr_args  { $$ = $3; }
491                        |  AUDIO_OUTPUT_CHANNEL_PARAMETER SP NUMBER SP NUMBER SP string EQ param_val  { $$ = LSCPSERVER->SetAudioOutputChannelParameter($3, $5, $7, $9); }                        |  ENGINE SP load_engine_args     { $$ = $3; }
                       |  CHANNEL SP set_chan_instruction                                                   { $$ = $3;                                                         }  
492                        ;                        ;
493    
494  create_instruction    :  AUDIO_OUTPUT_DEVICE SP string SP key_val_list { $$ = LSCPSERVER->CreateAudioOutputDevice($3,$5); }  append_instruction    :  SEND_EFFECT_CHAIN SP EFFECT SP device_index SP effect_chain SP effect_instance  { $$ = LSCPSERVER->AppendSendEffectChainEffect($5,$7,$9); }
                       |  AUDIO_OUTPUT_DEVICE SP string                 { $$ = LSCPSERVER->CreateAudioOutputDevice($3); }  
495                        ;                        ;
496    
497  destroy_instruction   :  AUDIO_OUTPUT_DEVICE SP NUMBER  { $$ = LSCPSERVER->DestroyAudioOutputDevice($3); }  insert_instruction    :  SEND_EFFECT_CHAIN SP EFFECT SP device_index SP effect_chain SP chain_pos SP effect_instance  { $$ = LSCPSERVER->InsertSendEffectChainEffect($5,$7,$9,$11); }
498                        ;                        ;
499    
500  load_instruction      :  INSTRUMENT SP load_instr_args  { $$ = $3; }  set_chan_instruction  :  AUDIO_OUTPUT_DEVICE SP sampler_channel SP device_index                                              { $$ = LSCPSERVER->SetAudioOutputDevice($5, $3);      }
501                        |  ENGINE SP load_engine_args     { $$ = $3; }                        |  AUDIO_OUTPUT_CHANNEL SP sampler_channel SP audio_channel_index SP audio_channel_index               { $$ = LSCPSERVER->SetAudioOutputChannel($5, $7, $3); }
502                          |  AUDIO_OUTPUT_TYPE SP sampler_channel SP audio_output_type_name                                      { $$ = LSCPSERVER->SetAudioOutputType($5, $3);        }
503                          |  MIDI_INPUT SP sampler_channel SP device_index SP midi_input_port_index SP midi_input_channel_index  { $$ = LSCPSERVER->SetMIDIInput($5, $7, $9, $3);      }
504                          |  MIDI_INPUT_DEVICE SP sampler_channel SP device_index                                                { $$ = LSCPSERVER->SetMIDIInputDevice($5, $3);        }
505                          |  MIDI_INPUT_PORT SP sampler_channel SP midi_input_port_index                                         { $$ = LSCPSERVER->SetMIDIInputPort($5, $3);          }
506                          |  MIDI_INPUT_CHANNEL SP sampler_channel SP midi_input_channel_index                                   { $$ = LSCPSERVER->SetMIDIInputChannel($5, $3);       }
507                          |  MIDI_INPUT_TYPE SP sampler_channel SP midi_input_type_name                                          { $$ = LSCPSERVER->SetMIDIInputType($5, $3);          }
508                          |  VOLUME SP sampler_channel SP volume_value                                                           { $$ = LSCPSERVER->SetVolume($5, $3);                 }
509                          |  MUTE SP sampler_channel SP boolean                                                                  { $$ = LSCPSERVER->SetChannelMute($5, $3);            }
510                          |  SOLO SP sampler_channel SP boolean                                                                  { $$ = LSCPSERVER->SetChannelSolo($5, $3);            }
511                          |  MIDI_INSTRUMENT_MAP SP sampler_channel SP midi_map                                                  { $$ = LSCPSERVER->SetChannelMap($3, $5);             }
512                          |  MIDI_INSTRUMENT_MAP SP sampler_channel SP NONE                                                      { $$ = LSCPSERVER->SetChannelMap($3, -1);             }
513                          |  MIDI_INSTRUMENT_MAP SP sampler_channel SP DEFAULT                                                   { $$ = LSCPSERVER->SetChannelMap($3, -2);             }
514                          ;
515    
516    edit_instruction      :  CHANNEL SP INSTRUMENT SP sampler_channel  { $$ = LSCPSERVER->EditSamplerChannelInstrument($5); }
517                        ;                        ;
518    
519  set_chan_instruction  :  AUDIO_OUTPUT_DEVICE SP sampler_channel SP NUMBER                                         { $$ = LSCPSERVER->SetAudioOutputDevice($5, $3);      }  format_instruction    :  INSTRUMENTS_DB  { $$ = LSCPSERVER->FormatInstrumentsDb(); }
                       |  AUDIO_OUTPUT_CHANNEL SP sampler_channel SP audio_output_channel SP audio_output_channel  { $$ = LSCPSERVER->SetAudioOutputChannel($5, $7, $3); }  
                       |  MIDI_INPUT_PORT SP sampler_channel SP midi_input_port                                    { $$ = LSCPSERVER->SetMIDIInputPort($5, $3);          }  
                       |  MIDI_INPUT_CHANNEL SP sampler_channel SP midi_input_channel                              { $$ = LSCPSERVER->SetMIDIInputChannel($5, $3);       }  
                       |  MIDI_INPUT_TYPE SP sampler_channel SP midi_input_type                                    { $$ = LSCPSERVER->SetMIDIInputType($5, $3);          }  
                       |  VOLUME SP sampler_channel SP volume                                                      { $$ = LSCPSERVER->SetVolume($5, $3);                 }  
520                        ;                        ;
521    
522  key_val_list          :  string EQ param_val                  { $$[$1] = $3;          }  modal_arg             :  /* epsilon (empty argument) */  { $$ = true;  }
523                        |  key_val_list SP string EQ param_val  { $$ = $1; $$[$3] = $5; }                        |  NON_MODAL SP                    { $$ = false; }
524                          ;
525    
526    key_val_list          :  string '=' param_val_list                  { $$[$1] = $3;          }
527                          |  key_val_list SP string '=' param_val_list  { $$ = $1; $$[$3] = $5; }
528                        ;                        ;
529    
530  buffer_size_type      :  BYTES       { $$ = fill_response_bytes;      }  buffer_size_type      :  BYTES       { $$ = fill_response_bytes;      }
531                        |  PERCENTAGE  { $$ = fill_response_percentage; }                        |  PERCENTAGE  { $$ = fill_response_percentage; }
532                        ;                        ;
533    
534  list_instruction      :  AUDIO_OUTPUT_DEVICES  { $$ = LSCPSERVER->GetAudioOutputDevices(); }  list_instruction      :  AUDIO_OUTPUT_DEVICES                               { $$ = LSCPSERVER->GetAudioOutputDevices();              }
535                          |  MIDI_INPUT_DEVICES                                 { $$ = LSCPSERVER->GetMidiInputDevices();                }
536                          |  CHANNELS                                           { $$ = LSCPSERVER->ListChannels();                       }
537                          |  CHANNEL SP MIDI_INPUTS SP sampler_channel          { $$ = LSCPSERVER->ListChannelMidiInputs($5);            }
538                          |  AVAILABLE_ENGINES                                  { $$ = LSCPSERVER->ListAvailableEngines();               }
539                          |  AVAILABLE_EFFECTS                                  { $$ = LSCPSERVER->ListAvailableEffects();               }
540                          |  EFFECT_INSTANCES                                   { $$ = LSCPSERVER->ListEffectInstances();                }
541                          |  SEND_EFFECT_CHAINS SP number                       { $$ = LSCPSERVER->ListSendEffectChains($3);             }
542                          |  AVAILABLE_MIDI_INPUT_DRIVERS                       { $$ = LSCPSERVER->ListAvailableMidiInputDrivers();      }
543                          |  AVAILABLE_AUDIO_OUTPUT_DRIVERS                     { $$ = LSCPSERVER->ListAvailableAudioOutputDrivers();    }
544                          |  MIDI_INSTRUMENTS SP midi_map                       { $$ = LSCPSERVER->ListMidiInstrumentMappings($3);       }
545                          |  MIDI_INSTRUMENTS SP ALL                            { $$ = LSCPSERVER->ListAllMidiInstrumentMappings();      }
546                          |  MIDI_INSTRUMENT_MAPS                               { $$ = LSCPSERVER->ListMidiInstrumentMaps();             }
547                          |  FX_SENDS SP sampler_channel                        { $$ = LSCPSERVER->ListFxSends($3);                      }
548                          |  DB_INSTRUMENT_DIRECTORIES SP RECURSIVE SP db_path  { $$ = LSCPSERVER->GetDbInstrumentDirectories($5, true); }
549                          |  DB_INSTRUMENT_DIRECTORIES SP db_path               { $$ = LSCPSERVER->GetDbInstrumentDirectories($3);       }
550                          |  DB_INSTRUMENTS SP RECURSIVE SP db_path             { $$ = LSCPSERVER->GetDbInstruments($5, true);           }
551                          |  DB_INSTRUMENTS SP db_path                          { $$ = LSCPSERVER->GetDbInstruments($3);                 }
552                          |  FILE SP INSTRUMENTS SP filename                    { $$ = LSCPSERVER->ListFileInstruments($5);              }
553                        ;                        ;
554    
555  load_instr_args       :  filename SP instrument_index SP sampler_channel  { $$ = LSCPSERVER->LoadInstrument($1, $3, $5); }  send_instruction      :  CHANNEL SP MIDI_DATA SP string SP sampler_channel SP number SP number  { $$ = LSCPSERVER->SendChannelMidiData($5, $7, $9, $11); }
556                          ;
557    
558    load_instr_args       :  filename SP instrument_index SP sampler_channel               { $$ = LSCPSERVER->LoadInstrument($1, $3, $5);       }
559                        |  NON_MODAL SP filename SP instrument_index SP sampler_channel  { $$ = LSCPSERVER->LoadInstrument($3, $5, $7, true); }                        |  NON_MODAL SP filename SP instrument_index SP sampler_channel  { $$ = LSCPSERVER->LoadInstrument($3, $5, $7, true); }
560                        ;                        ;
561    
562  load_engine_args      :  engine_name SP sampler_channel  { $$ = LSCPSERVER->LoadEngine($1, $3); }  load_engine_args      :  engine_name SP sampler_channel  { $$ = LSCPSERVER->SetEngineType($1, $3); }
563                          ;
564    
565    instr_load_mode       :  ON_DEMAND       { $$ = MidiInstrumentMapper::ON_DEMAND;      }
566                          |  ON_DEMAND_HOLD  { $$ = MidiInstrumentMapper::ON_DEMAND_HOLD; }
567                          |  PERSISTENT      { $$ = MidiInstrumentMapper::PERSISTENT;     }
568                          ;
569    
570    effect_instance           : number
571                              ;
572    
573    device_index              :  number
574                              ;
575    
576    audio_channel_index       :  number
577                              ;
578    
579    audio_output_type_name    :  string
580                              ;
581    
582    midi_input_port_index     :  number
583                              ;
584    
585    midi_input_channel_index  :  number
586                              |  ALL  { $$ = 16; }
587                              ;
588    
589    midi_input_type_name      :  string
590                              ;
591    
592    midi_map                  :  number
593                              ;
594    
595    midi_bank                 :  number
596                              ;
597    
598    midi_prog                 :  number
599                              ;
600    
601    midi_ctrl                 :  number
602                              ;
603    
604    volume_value              :  dotnum
605                              |  number  { $$ = $1; }
606                              ;
607    
608    control_value             :  real
609                              ;
610    
611    sampler_channel           :  number
612                              ;
613    
614    instrument_index          :  number
615                              ;
616    
617    fx_send_id                :  number
618                              ;
619    
620    engine_name               :  string
621                              ;
622    
623    filename                  :  path  {
624                                     #if WIN32
625                                     $$ = $1.toWindows();
626                                     #else
627                                     // assuming POSIX
628                                     $$ = $1.toPosix();
629                                     #endif
630                                 }
631                              ;
632    
633    db_path                   :  path  { $$ = $1.toDbPath(); }
634                              ;
635    
636    map_name                  :  stringval_escaped
637                              ;
638    
639    entry_name                :  stringval_escaped
640                              ;
641    
642    fx_send_name              :  stringval_escaped
643                              ;
644    
645    effect_name               :  stringval_escaped
646                              ;
647    
648    effect_index              :  number
649                              ;
650    
651    effect_chain              :  number
652                              ;
653    
654    chain_pos                 :  number
655                              ;
656    
657    input_control             :  number
658                              ;
659    
660    param_val_list            :  param_val
661                              |  param_val_list','param_val  { $$ = $1 + "," + $3; }
662                              ;
663    
664    //TODO: the re-encapsulation into apostrophes for string and strinval here is a hack, since we need a way for __parse_strings() (DeviceParameters.cpp) to distinguish a comma separated list of strings and a string which contains commas. A clean solution would be to move those parser jobs over here to lscp.y
665    param_val                 :  string            { $$ = "\'" + $1 + "\'"; }
666                              |  stringval         { $$ = "\'" + $1 + "\'"; }
667                              |  number            { std::stringstream ss; ss << "\'" << $1 << "\'"; $$ = ss.str(); }
668                              |  dotnum            { std::stringstream ss; ss << "\'" << $1 << "\'"; $$ = ss.str(); } //TODO: maybe better using 'real' instead of 'number' and 'dotnum' rules
669                              ;
670    
671    query_val_list            :  string '=' query_val                    { $$[$1] = $3;          }
672                              |  query_val_list SP string '=' query_val  { $$ = $1; $$[$3] = $5; }
673                              ;
674    
675    query_val                 :  text_escaped
676                              |  stringval_escaped
677                              ;
678    
679    scan_mode                 :  RECURSIVE      { $$ = "RECURSIVE"; }
680                              |  NON_RECURSIVE  { $$ = "NON_RECURSIVE"; }
681                              |  FLAT           { $$ = "FLAT"; }
682                              ;
683    
684    effect_system             :  string
685                              ;
686    
687    module                    :  filename
688                              ;
689    
690    // GRAMMAR_BNF_END - do NOT delete or modify this line !!!
691    
692    
693    // atomic variable symbol rules
694    
695    boolean               :  number  { $$ = $1; }
696                          |  string  { $$ = -1; }
697                          ;
698    
699    dotnum                :      digits '.' digits  { std::stringstream ss($1 + "." + $3); ss.imbue(std::locale::classic()); ss >> $$; }
700                          |  '+' digits '.' digits  { std::stringstream ss($2 + "." + $4); ss.imbue(std::locale::classic()); ss >> $$; }
701                          |  '-' digits '.' digits  { std::stringstream ss("-" + $2 + "." + $4); ss.imbue(std::locale::classic()); ss >> $$; }
702                          ;
703    
704    real                  :      digits '.' digits  { std::stringstream ss($1 + "." + $3); ss.imbue(std::locale::classic()); ss >> $$; }
705                          |  '+' digits '.' digits  { std::stringstream ss($2 + "." + $4); ss.imbue(std::locale::classic()); ss >> $$; }
706                          |  '-' digits '.' digits  { std::stringstream ss("-" + $2 + "." + $4); ss.imbue(std::locale::classic()); ss >> $$; }
707                          |      digits             { std::stringstream ss($1); ss.imbue(std::locale::classic()); ss >> $$;                  }
708                          |  '+' digits             { std::stringstream ss($2); ss.imbue(std::locale::classic()); ss >> $$;                  }
709                          |  '-' digits             { std::stringstream ss("-" + $2); ss.imbue(std::locale::classic()); ss >> $$;            }
710                          ;
711    
712    
713    digits                :  digit         { $$ = $1;      }
714                          |  digits digit  { $$ = $1 + $2; }
715                          ;
716    
717    digit                 :  '0'  { $$ = '0'; }
718                          |  '1'  { $$ = '1'; }
719                          |  '2'  { $$ = '2'; }
720                          |  '3'  { $$ = '3'; }
721                          |  '4'  { $$ = '4'; }
722                          |  '5'  { $$ = '5'; }
723                          |  '6'  { $$ = '6'; }
724                          |  '7'  { $$ = '7'; }
725                          |  '8'  { $$ = '8'; }
726                          |  '9'  { $$ = '9'; }
727                          ;
728    
729    digit_oct             :  '0'  { $$ = '0'; }
730                          |  '1'  { $$ = '1'; }
731                          |  '2'  { $$ = '2'; }
732                          |  '3'  { $$ = '3'; }
733                          |  '4'  { $$ = '4'; }
734                          |  '5'  { $$ = '5'; }
735                          |  '6'  { $$ = '6'; }
736                          |  '7'  { $$ = '7'; }
737                          ;
738    
739    digit_hex             :  '0'  { $$ = '0'; }
740                          |  '1'  { $$ = '1'; }
741                          |  '2'  { $$ = '2'; }
742                          |  '3'  { $$ = '3'; }
743                          |  '4'  { $$ = '4'; }
744                          |  '5'  { $$ = '5'; }
745                          |  '6'  { $$ = '6'; }
746                          |  '7'  { $$ = '7'; }
747                          |  '8'  { $$ = '8'; }
748                          |  '9'  { $$ = '9'; }
749                          |  'a'  { $$ = 'a'; }
750                          |  'b'  { $$ = 'b'; }
751                          |  'c'  { $$ = 'c'; }
752                          |  'd'  { $$ = 'd'; }
753                          |  'e'  { $$ = 'e'; }
754                          |  'f'  { $$ = 'f'; }
755                          |  'A'  { $$ = 'a'; }
756                          |  'B'  { $$ = 'b'; }
757                          |  'C'  { $$ = 'c'; }
758                          |  'D'  { $$ = 'd'; }
759                          |  'E'  { $$ = 'e'; }
760                          |  'F'  { $$ = 'f'; }
761                          ;
762    
763    number                :  digit       { $$ = atoi(String(1, $1).c_str());      }
764                          |  '1' digits  { $$ = atoi(String(String("1") + $2).c_str()); }
765                          |  '2' digits  { $$ = atoi(String(String("2") + $2).c_str()); }
766                          |  '3' digits  { $$ = atoi(String(String("3") + $2).c_str()); }
767                          |  '4' digits  { $$ = atoi(String(String("4") + $2).c_str()); }
768                          |  '5' digits  { $$ = atoi(String(String("5") + $2).c_str()); }
769                          |  '6' digits  { $$ = atoi(String(String("6") + $2).c_str()); }
770                          |  '7' digits  { $$ = atoi(String(String("7") + $2).c_str()); }
771                          |  '8' digits  { $$ = atoi(String(String("8") + $2).c_str()); }
772                          |  '9' digits  { $$ = atoi(String(String("9") + $2).c_str()); }
773                          ;
774    
775    path                  :  '\'' path_base '\''  { $$ = $2; }
776                          |  '\"' path_base '\"'  { $$ = $2; }
777                          ;
778    
779    path_base             :  path_prefix path_body  { $$ = $1 + $2; }
780                          ;
781    
782    path_prefix           :  '/'                 { $$ = Path();                    }
783                          |  alpha_char ':' '/'  { Path p; p.setDrive($1); $$ = p; }
784                          ;
785    
786    path_body             :  /* epsilon (empty argument) */ { $$ = Path();                           }
787                          |  path_body '/'                  { $$ = $1;                               }
788                          |  path_body text_escaped_base    { Path p; p.appendNode($2); $$ = $1 + p; }
789                          ;
790    
791    stringval             :  '\'' text '\''  { $$ = $2; }
792                          |  '\"' text '\"'  { $$ = $2; }
793                          ;
794    
795    stringval_escaped     :  '\'' text_escaped '\''  { $$ = $2; }
796                          |  '\"' text_escaped '\"'  { $$ = $2; }
797                          ;
798    
799    text                  :  SP           { $$ = " ";      }
800                          |  string
801                          |  text SP      { $$ = $1 + " "; }
802                          |  text string  { $$ = $1 + $2;  }
803                          ;
804    
805    // like text_escaped, but missing the slash ('/') character
806    text_escaped_base     :  SP                                { $$ = " ";      }
807                          |  string_escaped
808                          |  text_escaped_base SP              { $$ = $1 + " "; }
809                          |  text_escaped_base string_escaped  { $$ = $1 + $2;  }
810                          ;
811    
812    text_escaped          :  '/'                              { $$ = "/";      }
813                          |  text_escaped_base
814                          |  text_escaped '/'                 { $$ = $1 + "/"; }
815                          |  text_escaped text_escaped_base   { $$ = $1 + $2;  }
816                          ;
817    
818    string                :  char          { std::string s; s = $1; $$ = s; }
819                          |  string char   { $$ = $1 + $2;                  }
820                          ;
821    
822    string_escaped        :  char_base                   { std::string s; s = $1; $$ = s; }
823                          |  escape_seq                  { std::string s; s = $1; $$ = s; }
824                          |  string_escaped char_base    { $$ = $1 + $2;                  }
825                          |  string_escaped escape_seq   { $$ = $1 + $2;                  }
826                          ;
827    
828    // full ASCII character set except space, quotation mark and apostrophe
829    char                  :  char_base
830                          |  '\\'  { $$ = '\\'; }
831                          |  '/'   { $$ = '/';  }
832                          ;
833    
834    // characters A..Z and a..z
835    alpha_char            :  'A' { $$ = 'A'; } | 'B' { $$ = 'B'; } | 'C' { $$ = 'C'; } | 'D' { $$ = 'D'; } | 'E' { $$ = 'E'; } | 'F' { $$ = 'F'; } | 'G' { $$ = 'G'; } | 'H' { $$ = 'H'; } | 'I' { $$ = 'I'; } | 'J' { $$ = 'J'; } | 'K' { $$ = 'K'; } | 'L' { $$ = 'L'; } | 'M' { $$ = 'M'; } | 'N' { $$ = 'N'; } | 'O' { $$ = 'O'; } | 'P' { $$ = 'P'; } | 'Q' { $$ = 'Q'; } | 'R' { $$ = 'R'; } | 'S' { $$ = 'S'; } | 'T' { $$ = 'T'; } | 'U' { $$ = 'U'; } | 'V' { $$ = 'V'; } | 'W' { $$ = 'W'; } | 'X' { $$ = 'X'; } | 'Y' { $$ = 'Y'; } | 'Z' { $$ = 'Z'; }
836                          |  'a' { $$ = 'a'; } | 'b' { $$ = 'b'; } | 'c' { $$ = 'c'; } | 'd' { $$ = 'd'; } | 'e' { $$ = 'e'; } | 'f' { $$ = 'f'; } | 'g' { $$ = 'g'; } | 'h' { $$ = 'h'; } | 'i' { $$ = 'i'; } | 'j' { $$ = 'j'; } | 'k' { $$ = 'k'; } | 'l' { $$ = 'l'; } | 'm' { $$ = 'm'; } | 'n' { $$ = 'n'; } | 'o' { $$ = 'o'; } | 'p' { $$ = 'p'; } | 'q' { $$ = 'q'; } | 'r' { $$ = 'r'; } | 's' { $$ = 's'; } | 't' { $$ = 't'; } | 'u' { $$ = 'u'; } | 'v' { $$ = 'v'; } | 'w' { $$ = 'w'; } | 'x' { $$ = 'x'; } | 'y' { $$ = 'y'; } | 'z' { $$ = 'z'; }
837                          ;
838    
839    // ASCII characters except space, quotation mark, apostrophe, backslash and slash
840    char_base             :  alpha_char
841                          |  '0' { $$ = '0'; } | '1' { $$ = '1'; } | '2' { $$ = '2'; } | '3' { $$ = '3'; } | '4' { $$ = '4'; } | '5' { $$ = '5'; } | '6' { $$ = '6'; } | '7' { $$ = '7'; } | '8' { $$ = '8'; } | '9' { $$ = '9'; }
842                          |  '!' { $$ = '!'; } | '#' { $$ = '#'; } | '$' { $$ = '$'; } | '%' { $$ = '%'; } | '&' { $$ = '&'; } | '(' { $$ = '('; } | ')' { $$ = ')'; } | '*' { $$ = '*'; } | '+' { $$ = '+'; } | '-' { $$ = '-'; } | '.' { $$ = '.'; } | ',' { $$ = ','; }
843                          |  ':' { $$ = ':'; } | ';' { $$ = ';'; } | '<' { $$ = '<'; } | '=' { $$ = '='; } | '>' { $$ = '>'; } | '?' { $$ = '?'; } | '@' { $$ = '@'; }
844                          |  '[' { $$ = '['; } | ']' { $$ = ']'; } | '^' { $$ = '^'; } | '_' { $$ = '_'; }
845                          |  '{' { $$ = '{'; } | '|' { $$ = '|'; } | '}' { $$ = '}'; } | '~' { $$ = '~'; }
846                          |  EXT_ASCII_CHAR
847                          ;
848    
849    escape_seq            :  '\\' '\''  { $$ = '\''; }
850                          |  '\\' '\"'  { $$ = '\"'; }
851                          |  '\\' '\\'  { $$ = '\\'; }
852                          |  '\\' '/'   { $$ = '/';  }
853                          |  '\\' 'n'   { $$ = '\n'; }
854                          |  '\\' 'r'   { $$ = '\r'; }
855                          |  '\\' 'f'   { $$ = '\f'; }
856                          |  '\\' 't'   { $$ = '\t'; }
857                          |  '\\' 'v'   { $$ = '\v'; }
858                          |  escape_seq_octal
859                          |  escape_seq_hex
860                          ;
861    
862    escape_seq_octal      :  '\\' digit_oct                      { $$ = (char) octalsToNumber($2);       }
863                          |  '\\' digit_oct digit_oct            { $$ = (char) octalsToNumber($3,$2);    }
864                          |  '\\' digit_oct digit_oct digit_oct  { $$ = (char) octalsToNumber($4,$3,$2); }
865                          ;
866    
867    escape_seq_hex        :  '\\' 'x' digit_hex            { $$ = (char) hexsToNumber($3);    }
868                          |  '\\' 'x' digit_hex digit_hex  { $$ = (char) hexsToNumber($4,$3); }
869                          ;
870    
871    // rules which are more or less just terminal symbols
872    
873    SP                    :  ' '
874                          ;
875    
876    LF                    :  '\n'
877                          ;
878    
879    CR                    :  '\r'
880                          ;
881    
882    ADD                   :  'A''D''D'
883                          ;
884    
885    GET                   :  'G''E''T'
886                          ;
887    
888    MAP                   :  'M''A''P'
889                          ;
890    
891    UNMAP                 :  'U''N''M''A''P'
892                          ;
893    
894    CLEAR                 :  'C''L''E''A''R'
895                          ;
896    
897    FIND                  :  'F''I''N''D'
898                          ;
899    
900    FILE_AS_DIR           :  'F''I''L''E''_''A''S''_''D''I''R'
901                          ;
902    
903    MOVE                  :  'M''O''V''E'
904                          ;
905    
906    COPY                  :  'C''O''P''Y'
907                          ;
908    
909    CREATE                :  'C''R''E''A''T''E'
910                          ;
911    
912    DESTROY               :  'D''E''S''T''R''O''Y'
913                          ;
914    
915    LIST                  :  'L''I''S''T'
916                          ;
917    
918    LOAD                  :  'L''O''A''D'
919                          ;
920    
921    ALL                   :  'A''L''L'
922                          ;
923    
924    NONE                  :  'N''O''N''E'
925                          ;
926    
927    DEFAULT               :  'D''E''F''A''U''L''T'
928                          ;
929    
930    NON_MODAL             :  'N''O''N''_''M''O''D''A''L'
931                          ;
932    
933    REMOVE                :  'R''E''M''O''V''E'
934                          ;
935    
936    SET                   :  'S''E''T'
937                          ;
938    
939    SHELL                 :  'S''H''E''L''L'
940                          ;
941    
942    INTERACT              :  'I''N''T''E''R''A''C''T'
943                          ;
944    
945    AUTO_CORRECT          :  'A''U''T''O''_''C''O''R''R''E''C''T'
946                          ;
947    
948    APPEND                :  'A''P''P''E''N''D'
949                          ;
950    
951    INSERT                :  'I''N''S''E''R''T'
952                          ;
953    
954    SUBSCRIBE             :  'S''U''B''S''C''R''I''B''E'
955                          ;
956    
957    UNSUBSCRIBE           :  'U''N''S''U''B''S''C''R''I''B''E'
958                          ;
959    
960    CHANNEL               :  'C''H''A''N''N''E''L'
961                          ;
962    
963    AVAILABLE_ENGINES     :  'A''V''A''I''L''A''B''L''E''_''E''N''G''I''N''E''S'
964                          ;
965    
966    AVAILABLE_AUDIO_OUTPUT_DRIVERS  :  'A''V''A''I''L''A''B''L''E''_''A''U''D''I''O''_''O''U''T''P''U''T''_''D''R''I''V''E''R''S'
967                                    ;
968    
969    CHANNELS             :  'C''H''A''N''N''E''L''S'
970                         ;
971    
972    INFO                 :  'I''N''F''O'
973                         ;
974    
975    AUDIO_OUTPUT_DEVICE_COUNT :  'A''U''D''I''O''_''O''U''T''P''U''T''_''D''E''V''I''C''E''_''C''O''U''N''T'
976                              ;
977    
978    AUDIO_OUTPUT_DEVICE_INFO  :  'A''U''D''I''O''_''O''U''T''P''U''T''_''D''E''V''I''C''E''_''I''N''F''O'
979                              ;
980    
981    MIDI_INPUT_DEVICE_COUNT   :  'M''I''D''I''_''I''N''P''U''T''_''D''E''V''I''C''E''_''C''O''U''N''T'
982                              ;
983    
984    MIDI_INPUT_DEVICE_INFO    :  'M''I''D''I''_''I''N''P''U''T''_''D''E''V''I''C''E''_''I''N''F''O'
985                              ;
986    
987    MIDI_INSTRUMENT_MAP_COUNT :  'M''I''D''I''_''I''N''S''T''R''U''M''E''N''T''_''M''A''P''_''C''O''U''N''T'
988                              ;
989    
990    MIDI_INSTRUMENT_MAP_INFO  :  'M''I''D''I''_''I''N''S''T''R''U''M''E''N''T''_''M''A''P''_''I''N''F''O'
991                              ;
992    
993    MIDI_INSTRUMENT_COUNT     :  'M''I''D''I''_''I''N''S''T''R''U''M''E''N''T''_''C''O''U''N''T'
994                              ;
995    
996    MIDI_INSTRUMENT_INFO      :  'M''I''D''I''_''I''N''S''T''R''U''M''E''N''T''_''I''N''F''O'
997                              ;
998    
999    DB_INSTRUMENT_DIRECTORY_COUNT :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''D''I''R''E''C''T''O''R''Y''_''C''O''U''N''T'
1000                                  ;
1001    
1002    DB_INSTRUMENT_DIRECTORY_INFO  :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''D''I''R''E''C''T''O''R''Y''_''I''N''F''O'
1003                                  ;
1004    
1005    DB_INSTRUMENT_COUNT           :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''C''O''U''N''T'
1006                                  ;
1007    
1008    DB_INSTRUMENT_INFO            :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''I''N''F''O'
1009                                  ;
1010    
1011    DB_INSTRUMENT_FILES           :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''F''I''L''E''S'
1012                                  ;
1013    
1014    DB_INSTRUMENTS_JOB_INFO       :  'D''B''_''I''N''S''T''R''U''M''E''N''T''S''_''J''O''B''_''I''N''F''O'
1015                                  ;
1016    
1017    CHANNEL_COUNT        :  'C''H''A''N''N''E''L''_''C''O''U''N''T'
1018                         ;
1019    
1020    CHANNEL_MIDI         :  'C''H''A''N''N''E''L''_''M''I''D''I'
1021                         ;
1022    
1023    DEVICE_MIDI          :  'D''E''V''I''C''E''_''M''I''D''I'
1024                         ;
1025    
1026    CHANNEL_INFO         :  'C''H''A''N''N''E''L''_''I''N''F''O'
1027                         ;
1028    
1029    FX_SEND_COUNT        :  'F''X''_''S''E''N''D''_''C''O''U''N''T'
1030                         ;
1031    
1032    FX_SEND_INFO         :  'F''X''_''S''E''N''D''_''I''N''F''O'
1033                         ;
1034    
1035    BUFFER_FILL          :  'B''U''F''F''E''R''_''F''I''L''L'
1036                         ;
1037    
1038    STREAM_COUNT         :  'S''T''R''E''A''M''_''C''O''U''N''T'
1039                         ;
1040    
1041    VOICE_COUNT          :  'V''O''I''C''E''_''C''O''U''N''T'
1042                         ;
1043    
1044    TOTAL_STREAM_COUNT   :  'T''O''T''A''L''_''S''T''R''E''A''M''_''C''O''U''N''T'
1045                         ;
1046    
1047    TOTAL_VOICE_COUNT    :  'T''O''T''A''L''_''V''O''I''C''E''_''C''O''U''N''T'
1048                         ;
1049    
1050    TOTAL_VOICE_COUNT_MAX:  'T''O''T''A''L''_''V''O''I''C''E''_''C''O''U''N''T''_''M''A''X'
1051                         ;
1052    
1053    GLOBAL_INFO          :  'G''L''O''B''A''L''_''I''N''F''O'
1054                         ;
1055    
1056    EFFECT_INSTANCE_COUNT   :  'E''F''F''E''C''T''_''I''N''S''T''A''N''C''E''_''C''O''U''N''T'
1057                            ;
1058    
1059    EFFECT_INSTANCE_INFO    :  'E''F''F''E''C''T''_''I''N''S''T''A''N''C''E''_''I''N''F''O'
1060                            ;
1061    
1062    SEND_EFFECT_CHAIN_COUNT :  'S''E''N''D''_''E''F''F''E''C''T''_''C''H''A''I''N''_''C''O''U''N''T'
1063                            ;
1064    
1065    SEND_EFFECT_CHAIN_INFO  :  'S''E''N''D''_''E''F''F''E''C''T''_''C''H''A''I''N''_''I''N''F''O'
1066                            ;
1067    
1068    INSTRUMENT           :  'I''N''S''T''R''U''M''E''N''T'
1069                         ;
1070    
1071    INSTRUMENTS          :  'I''N''S''T''R''U''M''E''N''T''S'
1072                         ;
1073    
1074    ENGINE               :  'E' 'N' 'G' 'I' 'N' 'E'
1075                         ;
1076    
1077    ON_DEMAND            :  'O''N''_''D''E''M''A''N''D'
1078                         ;
1079    
1080    ON_DEMAND_HOLD       :  'O''N''_''D''E''M''A''N''D''_''H''O''L''D'
1081                         ;
1082    
1083    PERSISTENT           :  'P''E''R''S''I''S''T''E''N''T'
1084                         ;
1085    
1086    AUDIO_OUTPUT_DEVICE_PARAMETER  :  'A''U''D''I''O''_''O''U''T''P''U''T''_''D''E''V''I''C''E''_''P''A''R''A''M''E''T''E''R'
1087                                   ;
1088    
1089    AUDIO_OUTPUT_DEVICES  :  'A''U''D''I''O''_''O''U''T''P''U''T''_''D''E''V''I''C''E''S'
1090                          ;
1091    
1092    AUDIO_OUTPUT_DEVICE   :  'A''U''D''I''O''_''O''U''T''P''U''T''_''D''E''V''I''C''E'
1093                        ;                        ;
1094    
1095  midi_input_type       :  string  AUDIO_OUTPUT_DRIVER_PARAMETER  :  'A''U''D''I''O''_''O''U''T''P''U''T''_''D''R''I''V''E''R''_''P''A''R''A''M''E''T''E''R'
1096                                   ;
1097    
1098    AUDIO_OUTPUT_DRIVER   :  'A''U''D''I''O''_''O''U''T''P''U''T''_''D''R''I''V''E''R'
1099                        ;                        ;
1100    
1101  volume                :  DOTNUM  AUDIO_OUTPUT_CHANNEL_PARAMETER  :  'A''U''D''I''O''_''O''U''T''P''U''T''_''C''H''A''N''N''E''L''_''P''A''R''A''M''E''T''E''R'
1102                        |  NUMBER  { $$ = $1; }                                  ;
1103    
1104    AUDIO_OUTPUT_CHANNEL  :  'A''U''D''I''O''_''O''U''T''P''U''T''_''C''H''A''N''N''E''L'
1105                        ;                        ;
1106    
1107  sampler_channel       :  NUMBER  AUDIO_OUTPUT_TYPE     :  'A''U''D''I''O''_''O''U''T''P''U''T''_''T''Y''P''E'
1108                        ;                        ;
1109    
1110  instrument_index      :  NUMBER  AVAILABLE_EFFECTS :  'A''V''A''I''L''A''B''L''E''_''E''F''F''E''C''T''S'
1111                      ;
1112    
1113    EFFECT :  'E''F''F''E''C''T'
1114           ;
1115    
1116    EFFECT_INSTANCE :  'E''F''F''E''C''T''_''I''N''S''T''A''N''C''E'
1117                    ;
1118    
1119    EFFECT_INSTANCES :  'E''F''F''E''C''T''_''I''N''S''T''A''N''C''E''S'
1120                     ;
1121    
1122    EFFECT_INSTANCE_INPUT_CONTROL :  'E''F''F''E''C''T''_''I''N''S''T''A''N''C''E''_''I''N''P''U''T''_''C''O''N''T''R''O''L'
1123                                  ;
1124    
1125    SEND_EFFECT_CHAIN :  'S''E''N''D''_''E''F''F''E''C''T''_''C''H''A''I''N'
1126                      ;
1127    
1128    SEND_EFFECT_CHAINS :  'S''E''N''D''_''E''F''F''E''C''T''_''C''H''A''I''N''S'
1129                       ;
1130    
1131    AVAILABLE_MIDI_INPUT_DRIVERS  :  'A''V''A''I''L''A''B''L''E''_''M''I''D''I''_''I''N''P''U''T''_''D''R''I''V''E''R''S'
1132                                  ;
1133    
1134    MIDI_INPUT_DEVICE_PARAMETER  :  'M''I''D''I''_''I''N''P''U''T''_''D''E''V''I''C''E''_''P''A''R''A''M''E''T''E''R'
1135                                 ;
1136    
1137    MIDI_INPUT_PORT_PARAMETER    :  'M''I''D''I''_''I''N''P''U''T''_''P''O''R''T''_''P''A''R''A''M''E''T''E''R'
1138                                 ;
1139    
1140    MIDI_INPUT_DEVICES   :  'M''I''D''I''_''I''N''P''U''T''_''D''E''V''I''C''E''S'
1141                         ;
1142    
1143    MIDI_INPUT_DEVICE     :  'M''I''D''I''_''I''N''P''U''T''_''D''E''V''I''C''E'
1144                          ;
1145    
1146    MIDI_INPUT_DRIVER_PARAMETER  :  'M''I''D''I''_''I''N''P''U''T''_''D''R''I''V''E''R''_''P''A''R''A''M''E''T''E''R'
1147                                 ;
1148    
1149    MIDI_INSTRUMENT  :  'M''I''D''I''_''I''N''S''T''R''U''M''E''N''T'
1150                     ;
1151    
1152    MIDI_INSTRUMENTS  :  'M''I''D''I''_''I''N''S''T''R''U''M''E''N''T''S'
1153                      ;
1154    
1155    MIDI_INSTRUMENT_MAP  :  'M''I''D''I''_''I''N''S''T''R''U''M''E''N''T''_''M''A''P'
1156                         ;
1157    
1158    MIDI_INSTRUMENT_MAPS  :  'M''I''D''I''_''I''N''S''T''R''U''M''E''N''T''_''M''A''P''S'
1159                          ;
1160    
1161    MIDI_INPUT_DRIVER     :  'M''I''D''I''_''I''N''P''U''T''_''D''R''I''V''E''R'
1162                          ;
1163    
1164    MIDI_INPUT_PORT       :  'M''I''D''I''_''I''N''P''U''T''_''P''O''R''T'
1165                        ;                        ;
1166    
1167  audio_output_channel  :  NUMBER  MIDI_INPUT_CHANNEL    :  'M''I''D''I''_''I''N''P''U''T''_''C''H''A''N''N''E''L'
1168                        ;                        ;
1169    
1170  midi_input_channel    :  NUMBER  MIDI_INPUT_TYPE       :  'M''I''D''I''_''I''N''P''U''T''_''T''Y''P''E'
1171                        ;                        ;
1172    
1173  engine_name           :  string  MIDI_INPUT            :  'M''I''D''I''_''I''N''P''U''T'
1174                        ;                        ;
1175    
1176  midi_input_port       :  STRINGVAL  MIDI_INPUTS           :  'M''I''D''I''_''I''N''P''U''T''S'
1177                        ;                        ;
1178    
1179  filename              :  STRINGVAL  MIDI_CONTROLLER       :  'M''I''D''I''_''C''O''N''T''R''O''L''L''E''R'
1180                        ;                        ;
1181    
1182  param_val             :  STRINGVAL                { $$ = $1;                                             }  SEND                  :  'S''E''N''D'
                       |  NUMBER                   { std::stringstream ss; ss << $1; $$ = ss.str();       }  
                       |  DOTNUM                   { std::stringstream ss; ss << $1; $$ = ss.str();       }  
1183                        ;                        ;
1184    
1185  string                :  CHAR          { std::string s; s = $1; $$ = s; }  FX_SEND               :  'F''X''_''S''E''N''D'
1186                        |  string CHAR   { $$ = $1 + $2;                  }                        ;
1187    
1188    FX_SENDS              :  'F''X''_''S''E''N''D''S'
1189                          ;
1190    
1191    DB_INSTRUMENT_DIRECTORY    :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''D''I''R''E''C''T''O''R''Y'
1192                               ;
1193    
1194    DB_INSTRUMENT_DIRECTORIES  :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''D''I''R''E''C''T''O''R''I''E''S'
1195                               ;
1196    
1197    DB_INSTRUMENTS             :  'D''B''_''I''N''S''T''R''U''M''E''N''T''S'
1198                               ;
1199    
1200    DB_INSTRUMENT              :  'D''B''_''I''N''S''T''R''U''M''E''N''T'
1201                               ;
1202    
1203    DB_INSTRUMENTS_JOB         :  'D''B''_''I''N''S''T''R''U''M''E''N''T''S''_''J''O''B'
1204                               ;
1205    
1206    INSTRUMENTS_DB             :  'I''N''S''T''R''U''M''E''N''T''S''_''D''B'
1207                               ;
1208    
1209    DESCRIPTION                :  'D''E''S''C''R''I''P''T''I''O''N'
1210                               ;
1211    
1212    FORCE                      :  'F''O''R''C''E'
1213                               ;
1214    
1215    FLAT                       :  'F''L''A''T'
1216                               ;
1217    
1218    RECURSIVE                  :  'R''E''C''U''R''S''I''V''E'
1219                               ;
1220    
1221    NON_RECURSIVE              :  'N''O''N''_''R''E''C''U''R''S''I''V''E'
1222                               ;
1223    
1224    LOST                       :  'L''O''S''T'
1225                               ;
1226    
1227    FILE_PATH                  :  'F''I''L''E''_''P''A''T''H'
1228                               ;
1229    
1230    SERVER                :  'S''E''R''V''E''R'
1231                          ;
1232    
1233    VOLUME                :  'V''O''L''U''M''E'
1234                          ;
1235    
1236    LEVEL                 :  'L''E''V''E''L'
1237                          ;
1238    
1239    VALUE                 :  'V''A''L''U''E'
1240                          ;
1241    
1242    MUTE                  :  'M''U''T''E'
1243                          ;
1244    
1245    SOLO                  :  'S''O''L''O'
1246                          ;
1247    
1248    VOICES                :  'V''O''I''C''E''S'
1249                          ;
1250    
1251    STREAMS               :  'S''T''R''E''A''M''S'
1252                          ;
1253    
1254    BYTES                 :  'B''Y''T''E''S'
1255                          ;
1256    
1257    PERCENTAGE            :  'P''E''R''C''E''N''T''A''G''E'
1258                          ;
1259    
1260    FILE                  :  'F''I''L''E'
1261                          ;
1262    
1263    EDIT                  :  'E''D''I''T'
1264                          ;
1265    
1266    FORMAT                :  'F''O''R''M''A''T'
1267                          ;
1268    
1269    MIDI_DATA             :  'M''I''D''I''_''D''A''T''A'
1270                          ;
1271    
1272    RESET                 :  'R''E''S''E''T'
1273                          ;
1274    
1275    MISCELLANEOUS         :  'M''I''S''C''E''L''L''A''N''E''O''U''S'
1276                          ;
1277    
1278    NAME                  :  'N''A''M''E'
1279                          ;
1280    
1281    ECHO                  :  'E''C''H''O'
1282                          ;
1283    
1284    QUIT                  :  'Q''U''I''T'
1285                        ;                        ;
1286    
1287  %%  %%
1288    
1289    // TODO: actually would be fine to have the following bunch of source code in a separate file, however those functions are a) accessing private Bison tables like yytable and b) including the functions from another file here would make the line numbers incorrect on compile errors in auto generated lscpparser.cpp
1290    
1291  /**  /**
1292   * Will be called when an error occured (usually syntax error).   * Additional informations of a grammar symbol.
1293     */
1294    struct BisonSymbolInfo {
1295        bool isTerminalSymbol; ///< Whether the symbol is a terminal or non-termianl symbol. NOTE: Read comment regarding this in _isRuleTerminalSymbol() !!
1296        String nextExpectedChars; ///< According to current parser position: sequence of characters expected next for satisfying this grammar symbol.
1297    };
1298    
1299    #if HAVE_BISON_MAJ >= 3 // Bison 3.x or younger ...
1300    
1301    /**
1302     * Must ONLY be called just before a so called "reduce" parser action:
1303     * Returns true if the grammar rule, which is just about to be "reduced", is a
1304     * terminal symbol (in *our* terms).
1305     *
1306     * Please note that the term "terminal symbol" is a bit confusingly used in
1307     * this source code here around. In Bison's terms, "terminal symbols" are (more
1308     * or less) just the numbers returned by the YYLEX function. Since we decided
1309     * though to use a convenient solution without a separate lexer, and all its
1310     * caveats, all numbers by the yylex() function here are just the ASCII
1311     * numbers of the individual characters received. Based on that however, one
1312     * single character is not what one would intuitively expect of being a
1313     * "terminal symbol", because it is simply too primitive.
1314     *
1315     * So in this LSCP parser source code a "terminal symbol" rather means a
1316     * keyword like "CREATE" or "GET". In the grammal definition above, those are
1317     * however defined as grammar rules (non-terminals in Bison's terms). So this
1318     * function decides like this: if the given grammar rule just contains
1319     * individual characters on the right side of its grammar rule, then it is a
1320     * "terminal symbol" in *our* terms.
1321     *
1322     * @param rule - Bison grammar rule number
1323     * @param stack - reflecting current Bison parser state
1324     */
1325    inline static bool _isRuleTerminalSymbol(int rule, const std::vector<YYTYPE_INT16>& stack) {
1326        int nrhs = yyr2[rule];
1327        for (int i = 0; i < nrhs; ++i)
1328            if (yystos[*(stack.end() - nrhs + i)] >= YYNTOKENS) return false;
1329        return true;
1330    }
1331    
1332    /**
1333     * Must ONLY be called just before a so called "reduce" parser action: Returns
1334     * additional informations to the given grammar rule that is about to be
1335     * "reduced".
1336     *
1337     * @param rule - Bison grammar rule number
1338     * @param stack - reflecting current Bison parser state
1339     * @param nextExpectedChars - must already be filled with the characters
1340     *                            expected to be coming next
1341     */
1342    inline static BisonSymbolInfo _symbolInfoForRule(int rule, const std::vector<YYTYPE_INT16>& stack, const String& nextExpectedChars) {
1343        BisonSymbolInfo info;
1344        info.isTerminalSymbol = _isRuleTerminalSymbol(rule, stack);
1345        if (info.isTerminalSymbol) info.nextExpectedChars  = nextExpectedChars;
1346        return info;
1347    }
1348    
1349    #else // Bison 2.x or older ...
1350    
1351    /**
1352     * Returns true if the given grammar @a rule is a terminal symbol (in *our*
1353     * terms).
1354     *
1355     * Please note that the term "terminal symbol" is a bit confusingly used in
1356     * this source code here around. In Bison's terms, "terminal symbols" are (more
1357     * or less) just the numbers returned by the YYLEX function. Since we decided
1358     * though to use a convenient solution without a separate lexer, and all its
1359     * caveats, all numbers by the yylex() function here are just the ASCII
1360     * numbers of the individual characters received. Based on that however, one
1361     * single character is not what one would intuitively expect of being a
1362     * "terminal symbol", because it is simply too primitive.
1363     *
1364     * So in this LSCP parser source code a "terminal symbol" rather means a
1365     * keyword like "CREATE" or "GET". In the grammal definition above, those are
1366     * however defined as grammar rules (non-terminals in Bison's terms). So this
1367     * function decides like this: if the given grammar rule just contains
1368     * individual characters on the right side of its grammar rule, then it is a
1369     * "terminal symbol" in *our* terms.
1370     *
1371     * @param rule - Bison grammar rule number
1372     */
1373    inline static bool _isRuleTerminalSymbol(int rule) {
1374        for (int i = yyprhs[rule]; yyrhs[i] != -1; ++i)
1375            if (yyrhs[i] >= YYNTOKENS) return false;
1376        return true;
1377    }
1378    
1379    /**
1380     * Returns additional informations to the given grammar @a rule.
1381     *
1382     * @param rule - grammar rule index to retrieve informations about
1383     * @param nextExpectedChars - must already be filled with the characters
1384     *                            expected to be coming next
1385     */
1386    inline static BisonSymbolInfo _symbolInfoForRule(int rule, const String& nextExpectedChars) {
1387        BisonSymbolInfo info;
1388        info.isTerminalSymbol = _isRuleTerminalSymbol(rule);
1389        if (info.isTerminalSymbol) info.nextExpectedChars  = nextExpectedChars;
1390        return info;
1391    }
1392    
1393    #endif // HAVE_BISON_MAJ >= 3
1394    
1395    /**
1396     * Returns the human readable name of the given @a token.
1397     */
1398    inline static String _tokenName(int token) {
1399        String s = yytname[token];
1400        // remove leading and trailing apostrophes that Bison usually adds to
1401        // ASCII characters used directly in grammar rules
1402        if (s.empty()) return s;
1403        if (s[0] == '\'') s.erase(0, 1);
1404        if (s.empty()) return s;
1405        if (s[s.size() - 1] == '\'') s.erase(s.size() - 1);
1406        return s;
1407    }
1408    
1409    /**
1410     * Assumes the given @a token is exactly one character and returns that
1411     * character. This must be changed in future, i.e. in case Unicode characters
1412     * will be introduced in the LSCP grammar one day.
1413     */
1414    inline static char _tokenChar(int token) {
1415        String s = _tokenName(token);
1416        if (s == "\\n") return '\n';
1417        if (s == "\\r") return '\r';
1418        return _tokenName(token)[0];
1419    }
1420    
1421    /**
1422     * Implements Bison's so called "reduce" action, according to Bison's LALR(1)
1423     * parser algorithm.
1424   */   */
1425  void yyerror(const char* s) {  inline static int _yyReduce(std::vector<YYTYPE_INT16>& stack, const int& rule) {
1426      dmsg(2,("LSCPParser: %s\n", s));      if (stack.empty()) throw 1; // severe error
1427        const int len = yyr2[rule];
1428        stack.resize(stack.size() - len);
1429        YYTYPE_INT16 newState = yypgoto[yyr1[rule] - YYNTOKENS] + stack.back();
1430        if (0 <= newState && newState <= YYLAST && yycheck[newState] == stack.back())
1431            newState = yytable[newState];
1432        else
1433            newState = yydefgoto[yyr1[rule] - YYNTOKENS];
1434        stack.push_back(newState);
1435        return newState;
1436  }  }
1437    
1438  /**  /**
1439   * Clears input buffer and restarts scanner.   * Implements Bison's so called "default reduce" action, according to Bison's
1440     * LALR(1) parser algorithm.
1441     */
1442    inline static int _yyDefaultReduce(std::vector<YYTYPE_INT16>& stack) {
1443        if (stack.empty()) throw 2; // severe error
1444        int rule = yydefact[stack.back()];
1445        if (rule <= 0 || rule >= YYNRULES) throw 3; // no rule, something is wrong
1446        return _yyReduce(stack, rule);
1447    }
1448    
1449    static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch);
1450    
1451    #define DEBUG_BISON_SYNTAX_ERROR_WALKER 0
1452    
1453    /**
1454     * Tries to find the next expected grammar symbols according to the given
1455     * precise parse position & state represented by @a stack, according to Bison's
1456     * LALR(1) parser algorithm.
1457     *
1458     * This function is given a Bison parser state stack, reflecting the parser's
1459     * entire state at a certain point, i.e. when a syntax error occured. This
1460     * function will then walk ahead the potential parse tree starting from the
1461     * current head of the given state stack. This function will call itself
1462     * recursively to scan the individual parse tree branches. As soon as it hits
1463     * on the next non-terminal grammar symbol in one parse tree branch, it adds the
1464     * found non-terminal symbol to @a expectedSymbols and aborts scanning the
1465     * respective tree branch further. If any local parser state is reached a second
1466     * time, the respective parse tree is aborted to avoid any endless recursion.
1467     *
1468     * @param stack - current Bison (yacc) state stack to be examined
1469     * @param expectedSymbols - will be filled with next expected grammar symbols
1470     * @param nextExpectedChars - just for internal purpose, due to the recursive
1471     *                            implementation of this function, do supply an
1472     *                            empty character for this argument
1473     * @param depth - just for internal debugging purposes
1474     */
1475    static void walkAndFillExpectedSymbols(
1476        std::vector<YYTYPE_INT16>& stack,
1477        std::map<String,BisonSymbolInfo>& expectedSymbols,
1478        String& nextExpectedChars, int depth = 0)
1479    {
1480    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1481        printf("\n");
1482        for (int i = 0; i < depth; ++i) printf("\t");
1483        printf("State stack:");
1484        for (int i = 0; i < stack.size(); ++i) {
1485            printf(" %d", stack[i]);
1486        }
1487        printf("\n");
1488    #endif
1489        startLabel:
1490    
1491        if (stack.empty()) {
1492    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1493            for (int i = 0; i < depth; ++i) printf("\t");
1494            printf("(EMPTY STACK)\n");
1495    #endif
1496            return;
1497        }
1498    
1499        int state = stack[stack.size() - 1];
1500        int n = yypact[state];
1501        if (n == YYPACT_NINF) { // default reduction required ...
1502            // get default reduction rule for this state
1503            n = yydefact[state];
1504            if (n <= 0 || n >= YYNRULES) {
1505    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1506                for (int i = 0; i < depth; ++i) printf("\t");
1507                printf("(EMPTY RULE)\n");
1508    #endif
1509                return; // no rule, something is wrong
1510            }
1511    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1512            for (int i = 0; i < depth; ++i) printf("\t");
1513            printf("(default reduction)\n");
1514    #endif
1515            if (!nextExpectedChars.empty() || !_isRuleTerminalSymbol(n, stack)) {
1516                // Return the new resolved expected symbol (left-hand symbol of grammar
1517                // rule), then we're done in this state. (If the same symbol can be
1518                // matched on different ways, then it is non-terminal symbol.)
1519                bool ambigious =
1520                    expectedSymbols.count(yytname[yyr1[n]]) &&
1521                    expectedSymbols[yytname[yyr1[n]]].nextExpectedChars != nextExpectedChars;
1522                #if HAVE_BISON_MAJ >= 3
1523                expectedSymbols[yytname[yyr1[n]]] = _symbolInfoForRule(n, stack, nextExpectedChars);
1524                #else
1525                expectedSymbols[yytname[yyr1[n]]] = _symbolInfoForRule(n, nextExpectedChars);
1526                #endif
1527                if (ambigious)
1528                    expectedSymbols[yytname[yyr1[n]]].isTerminalSymbol = false;
1529    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1530                for (int i = 0; i < depth; ++i) printf("\t");
1531                printf("(empty expectedChars. sym = %s)\n", yytname[yyr1[n]]);
1532    #endif
1533                return;
1534            }
1535            _yyReduce(stack, n);
1536            goto startLabel;
1537        }
1538        if (!(YYPACT_NINF < n && n <= YYLAST)) {
1539    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1540            for (int i = 0; i < depth; ++i) printf("\t");
1541            printf("(invalid action B)\n");
1542    #endif
1543            return;
1544        }
1545    
1546        // Check for duplicate states, if duplicates exist return
1547        // (this check is necessary since the introduction of the yyValid() call
1548        // below, which does not care about duplicates).
1549        for (int i = 0; i < stack.size(); ++i)
1550            for (int k = i + 1; k < stack.size(); ++k)
1551                if (stack[i] == stack[k])
1552                    return;
1553    
1554    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1555        for (int i = 0; i < depth; ++i) printf("\t");
1556        printf("Expected tokens:");
1557    #endif
1558        int begin = n < 0 ? -n : 0;
1559        //int checklim = YYLAST - n + 1;
1560        int end = YYNTOKENS;//checklim < YYNTOKENS ? checklim : YYNTOKENS;
1561        int rule, action, stackSize, nextExpectedCharsLen;
1562        for (int token = begin; token < end; ++token) {
1563            if (token <= YYTERROR) continue;
1564            if (yytname[token] == String("$undefined")) continue;
1565            if (yytname[token] == String("EXT_ASCII_CHAR")) continue;
1566            //if (yycheck[n + token] != token) goto default_reduction;
1567            if (yycheck[n + token] != token) { // default reduction suggested ...
1568                // If we are here, it means the current token in the loop would not
1569                // cause a "shift", however we don't already know whether this token
1570                // is valid or not. Because there might be several reductions
1571                // involved until one can determine whether the token causes an
1572                // error or is valid. So we use this heavy check instead:
1573                std::vector<YYTYPE_INT16> stackCopy = stack; // copy required, since reduction will take place
1574                if (!yyValid(stackCopy, _tokenChar(token))) continue; // invalid token
1575    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1576                printf(" ETdr(%s)", yytname[token]);
1577    #endif
1578                // the token is valid, "stackCopy" has been reduced accordingly
1579                // and now do recurse ...
1580                nextExpectedChars += _tokenName(token);
1581                nextExpectedCharsLen = nextExpectedChars.size();
1582                walkAndFillExpectedSymbols( //FIXME: could cause stack overflow (should be a loop instead), is probably fine with our current grammar though
1583                    stackCopy, expectedSymbols, nextExpectedChars, depth + 1
1584                );
1585                nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'
1586                continue;
1587            }
1588    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1589            printf(" ET(%s)", yytname[token]);
1590    #endif
1591    
1592            action = yytable[n + token];
1593            if (action == 0 || action == YYTABLE_NINF) {
1594    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1595                printf(" (invalid action A) "); fflush(stdout);
1596    #endif
1597                continue; // error, ignore
1598            }
1599            if (action < 0) { // reduction with rule -action required ...
1600    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1601                printf(" (reduction) "); fflush(stdout);
1602    #endif
1603                rule = -action;
1604                goto reduce;
1605            }
1606            if (action == YYFINAL) {
1607    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1608                printf(" (ACCEPT) "); fflush(stdout);
1609    #endif
1610                continue; // "accept" state, we don't care about it here
1611            }
1612    
1613            // "shift" required ...
1614    
1615            if (std::find(stack.begin(), stack.end(), action) != stack.end()) {
1616    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1617                printf(" (duplicate state %d) ", action); fflush(stdout);
1618    #endif
1619                continue; // duplicate state, ignore it to avoid endless recursions
1620            }
1621    
1622            // "shift" / push the new state on the state stack and call this
1623            // function recursively, and restore the stack after the recurse return
1624            stackSize = stack.size();
1625            nextExpectedCharsLen = nextExpectedChars.size();
1626            stack.push_back(action);
1627            nextExpectedChars += _tokenName(token);
1628            walkAndFillExpectedSymbols( //FIXME: could cause stack overflow (should be a loop instead), is probably fine with our current grammar though
1629                stack, expectedSymbols, nextExpectedChars, depth + 1
1630            );
1631            stack.resize(stackSize); // restore stack
1632            nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'
1633            continue;
1634    
1635        //default_reduction: // resolve default reduction for this state
1636        //    printf(" (default red.) "); fflush(stdout);
1637        //    rule = yydefact[state];
1638    
1639        reduce: // "reduce" required
1640    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1641            printf(" (reduce by %d) ", rule); fflush(stdout);
1642    #endif
1643            if (rule == 0 || rule >= YYNRULES) {
1644    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1645                printf(" (invalid rule) "); fflush(stdout);
1646    #endif
1647                continue; // invalid rule, something is wrong
1648            }
1649            // Store the left-hand symbol of the grammar rule. (If the same symbol
1650            // can be matched on different ways, then it is non-terminal symbol.)
1651            bool ambigious =
1652                expectedSymbols.count(yytname[yyr1[rule]]) &&
1653                expectedSymbols[yytname[yyr1[rule]]].nextExpectedChars != nextExpectedChars;
1654            #if HAVE_BISON_MAJ >= 3
1655            expectedSymbols[yytname[yyr1[rule]]] = _symbolInfoForRule(rule, stack, nextExpectedChars);
1656            #else
1657            expectedSymbols[yytname[yyr1[rule]]] = _symbolInfoForRule(rule, nextExpectedChars);
1658            #endif
1659            if (ambigious)
1660                expectedSymbols[yytname[yyr1[n]]].isTerminalSymbol = false;
1661    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1662            printf(" (SYM %s) ", yytname[yyr1[rule]]); fflush(stdout);
1663    #endif
1664        }
1665    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1666        printf("\n");
1667    #endif
1668    }
1669    
1670    #define DEBUG_PUSH_PARSE 0
1671    
1672    /**
1673     * Implements parsing exactly one character (given by @a c), continueing at the
1674     * parser position reflected by @a stack. The @a stack will hold the new parser
1675     * state after this call.
1676     *
1677     * This function is implemented according to Bison's LALR(1) parser algorithm.
1678     */
1679    static bool yyPushParse(std::vector<YYTYPE_INT16>& stack, char ch) {
1680        startLabel:
1681    
1682    #if DEBUG_PUSH_PARSE
1683        //printf("\n");
1684        //for (int i = 0; i < depth; ++i) printf("\t");
1685        printf("State stack:");
1686        for (int i = 0; i < stack.size(); ++i) {
1687            printf(" %d", stack[i]);
1688        }
1689        printf(" char='%c'(%d)\n", ch, (int)ch);
1690    #endif
1691    
1692        if (stack.empty()) return false;
1693    
1694        int state = stack.back();
1695        int n = yypact[state];
1696        if (n == YYPACT_NINF) { // default reduction required ...
1697    #if DEBUG_PUSH_PARSE
1698            printf("(def reduce 1)\n");
1699    #endif
1700            state = _yyDefaultReduce(stack);
1701            goto startLabel;
1702        }
1703        if (!(YYPACT_NINF < n && n <= YYLAST)) return false;
1704    
1705        YYTYPE_INT16 token = (ch == YYEOF) ? YYEOF : yytranslate[ch];
1706        n += token;
1707        if (n < 0 || YYLAST < n || yycheck[n] != token) {
1708    #if DEBUG_PUSH_PARSE
1709            printf("(def reduce 2) n=%d token=%d\n", n, token);
1710    #endif
1711            state = _yyDefaultReduce(stack);
1712            goto startLabel;
1713        }
1714        int action = yytable[n]; // yytable[yypact[state] + token]
1715        if (action == 0 || action == YYTABLE_NINF) throw 4;
1716        if (action < 0) {
1717    #if DEBUG_PUSH_PARSE
1718            printf("(reduce)\n");
1719    #endif
1720            int rule = -action;
1721            state = _yyReduce(stack, rule);
1722            goto startLabel;
1723        }
1724        if (action == YYFINAL) return true; // final state reached
1725    
1726    #if DEBUG_PUSH_PARSE
1727        printf("(push)\n");
1728    #endif
1729        // push new state
1730        state = action;
1731        stack.push_back(state);
1732        return true;
1733    }
1734    
1735    /**
1736     * Returns true if parsing ahead with given character @a ch is syntactically
1737     * valid according to the LSCP grammar, it returns false if it would create a
1738     * parse error.
1739     *
1740     * The @a stack will reflect the new parser state after this call.
1741     *
1742     * This is just a wrapper ontop of yyPushParse() which converts parser
1743     * exceptions thrown by yyPushParse() into negative return value.
1744     */
1745    static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch) {
1746        try {
1747            return yyPushParse(stack, ch);
1748        } catch (int i) {
1749    #if DEBUG_PUSH_PARSE
1750            printf("exception %d\n", i);
1751    #endif
1752            return false;
1753        } catch (...) {
1754            return false;
1755        }
1756    }
1757    
1758    /**
1759     * Returns the amount of correct characters of given @a line from the left,
1760     * according to the LSCP grammar.
1761     *
1762     * @param stack - a Bison symbol state stack to work with
1763     * @param line  - the input line to check
1764     * @param bAutoCorrect - if true: try to correct obvious, trivial syntax errors
1765     */
1766    static int yyValidCharacters(std::vector<YYTYPE_INT16>& stack, String& line, bool bAutoCorrect) {
1767        int i;
1768        for (i = 0; i < line.size(); ++i) {
1769            // since we might check the same parser state twice against the current
1770            // char here below, and since the state stack might be altered
1771            // (i.e. shifted or reduced) on syntax errors, we have to backup the
1772            // current state stack and restore it on syntax errors below
1773            std::vector<YYTYPE_INT16> stackCopy = stack;
1774            if (yyValid(stackCopy, line[i])) {
1775                stack = stackCopy;
1776                continue;
1777            }
1778            if (bAutoCorrect) {
1779                // try trivial corrections, i.e. upper case character instead of
1780                // lower case, subline instead of space and vice versa
1781                char c;
1782                if      (line[i] == ' ') c = '_';
1783                else if (line[i] == '_') c = ' ';
1784                else if (isLowerCaseAlphaChar(line[i]))
1785                    c = alphaCharToUpperCase(line[i]);
1786                else return i;
1787                if (yyValid(stack, c)) {
1788                    line[i] = c;
1789                    continue;
1790                }
1791            }
1792            return i;
1793        }
1794        return i;
1795    }
1796    
1797    /**
1798     * Should only be called on syntax errors: returns a set of non-terminal
1799     * symbols expected to appear now/next, just at the point where the syntax
1800     * error appeared.
1801     *
1802     * @returns names of the non-terminal symbols expected at this parse position
1803     */
1804    static std::set<String> yyExpectedSymbols() {
1805        std::map<String,BisonSymbolInfo> expectedSymbols;
1806        yyparse_param_t* param = GetCurrentYaccSession();
1807        YYTYPE_INT16* ss = (*param->ppStackBottom);
1808        YYTYPE_INT16* sp = (*param->ppStackTop);
1809        int iStackSize   = sp - ss + 1;
1810        // copy and wrap parser's state stack into a convenient STL container
1811        std::vector<YYTYPE_INT16> stack;
1812        for (int i = 0; i < iStackSize; ++i) {
1813            stack.push_back(ss[i]);
1814        }
1815        String notUsedHere;
1816        // do the actual parser work
1817        walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere);
1818    
1819        // convert expectedSymbols to the result set
1820        std::set<String> result;
1821        for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1822             it != expectedSymbols.end(); ++it) result.insert(it->first);
1823        return result;
1824    }
1825    
1826    #define DEBUG_YY_AUTO_COMPLETE 0
1827    
1828    /**
1829     * A set of parser state stacks. This type is used in yyAutoComplete() to keep
1830     * track of all previous parser states, for detecting a parser state stack that
1831     * has already been before. Because if yyAutoComplete() reaches the exactly same
1832     * parser state stack again, it means there is an endless recursion in that
1833     * part of the grammar tree branch and shall not be evaluated any further,
1834     * because it would end up in an endless loop otherwise.
1835     *
1836     * This solution consumes a lot of memory, but unfortunately there is no other
1837     * easy way to solve it. With our grammar and today's memory heap & memory stack
1838     * it should be fine though.
1839     */
1840    typedef std::set< std::vector<YYTYPE_INT16> > YYStackHistory;
1841    
1842    /**
1843     * Generates and returns an auto completion string for the current parser
1844     * state given by @a stack.
1845     *
1846     * Regarding @a history argument: read the description on YYStackHistory for the
1847     * purpose behind this argument.
1848     *
1849     * @param stack - current Bison (yacc) state stack to create auto completion for
1850     * @param history - only for internal purpose, keeps a history of all previous parser state stacks
1851     * @param depth - just for internal debugging purposes
1852     * @returns auto completion for current, given parser state
1853     */
1854    static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack, YYStackHistory& history, int depth = 0) {
1855        std::map<String,BisonSymbolInfo> expectedSymbols;
1856        String notUsedHere;
1857        walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere);
1858        if (expectedSymbols.size() == 1) {
1859            String name          = expectedSymbols.begin()->first;
1860            BisonSymbolInfo info = expectedSymbols.begin()->second;
1861    #if DEBUG_YY_AUTO_COMPLETE
1862            for (int q = 0; q < depth; ++q) printf("  ");
1863            printf("(%d) Suggested Sub Completion (sz=%d): type=%s %s -> '%s'\n", depth, expectedSymbols.size(), (info.isTerminalSymbol) ? "T" : "NT", name.c_str(), info.nextExpectedChars.c_str());
1864    #endif
1865            if (info.nextExpectedChars.empty() || !info.isTerminalSymbol) return "";
1866            // parse forward with the suggested auto completion
1867            std::vector<YYTYPE_INT16> stackCopy = stack;
1868            yyValidCharacters(stackCopy, info.nextExpectedChars, false);
1869            // detect endless recursion
1870            if (history.count(stackCopy)) return "";
1871            history.insert(stackCopy);
1872            // recurse and return the expanded auto completion with maximum length
1873            return info.nextExpectedChars + yyAutoComplete(stackCopy, history, depth + 1);
1874        } else if (expectedSymbols.size() == 0) {
1875    #if DEBUG_YY_AUTO_COMPLETE
1876            for (int q = 0; q < depth; ++q) printf("  ");
1877            printf("(%d) No sub suggestion.\n", depth);
1878    #endif
1879            return "";
1880        } else if (expectedSymbols.size() > 1) {
1881    #if DEBUG_YY_AUTO_COMPLETE
1882            for (int q = 0; q < depth; ++q) printf("  ");
1883            printf("(%d) Multiple sub possibilities (before expansion):", depth);
1884            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1885                 it != expectedSymbols.end(); ++it)
1886            {
1887                printf(" %s (..%s)", it->first.c_str(), it->second.nextExpectedChars.c_str());
1888            }
1889            printf("\n");
1890    #endif
1891            // check if any of the possibilites is a non-terminal symbol, if so, we
1892            // have no way for auto completion at this point
1893            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1894                 it != expectedSymbols.end(); ++it)
1895            {
1896                if (!it->second.isTerminalSymbol) {
1897    #if DEBUG_YY_AUTO_COMPLETE
1898                    for (int q = 0; q < depth; ++q) printf("  ");
1899                    printf("(%d) Non-terminal exists. Stop.", depth);
1900    #endif
1901                    return "";
1902                }
1903            }
1904    #if 0 // commented out for now, since practically irrelevant and VERY slow ...
1905            // all possibilities are terminal symbols, so expand all possiblities to
1906            // maximum length with a recursive call for each possibility
1907            for (std::map<String,BisonSymbolInfo>::iterator it = expectedSymbols.begin();
1908                 it != expectedSymbols.end(); ++it)
1909            {
1910                if (it->second.nextExpectedChars.empty() || !it->second.isTerminalSymbol) continue;
1911                // parse forward with this particular suggested auto completion
1912                std::vector<YYTYPE_INT16> stackCopy = stack;
1913                yyValidCharacters(stackCopy, it->second.nextExpectedChars, false);
1914                // detect endless recursion
1915                if (history.count(stackCopy)) continue;
1916                history.insert(stackCopy);
1917                // recurse and return the total possible auto completion for this
1918                // grammar tree branch
1919                it->second.nextExpectedChars += yyAutoComplete(stackCopy, history, depth + 1);
1920            }
1921    #endif
1922            // try to find the longest common string all possibilities start with
1923            // (from the left)
1924            String sCommon;
1925            for (int i = 0; true; ++i) {
1926                char c;
1927                for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1928                     it != expectedSymbols.end(); ++it)
1929                {
1930                    if (i >= it->second.nextExpectedChars.size())
1931                        goto commonSearchEndLabel;
1932                    if (it == expectedSymbols.begin())
1933                        c = it->second.nextExpectedChars[i];
1934                    if (c != it->second.nextExpectedChars[i])
1935                        goto commonSearchEndLabel;
1936                    if (it == --expectedSymbols.end())
1937                        sCommon += c;
1938                }
1939            }
1940            commonSearchEndLabel:
1941    #if DEBUG_YY_AUTO_COMPLETE
1942            for (int q = 0; q < depth; ++q) printf("  ");
1943            printf("(%d) Multiple sub possibilities (after expansion):", depth);
1944            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1945                 it != expectedSymbols.end(); ++it)
1946            {
1947                printf(" %s (..%s)", it->first.c_str(), it->second.nextExpectedChars.c_str());
1948            }
1949            printf("\n");
1950            for (int q = 0; q < depth; ++q) printf("  ");
1951            printf("(%d) Common sub possibility: '%s'\n", depth, sCommon.c_str());
1952    #endif
1953            return sCommon;
1954        }
1955        return ""; // just pro forma, should never happen though
1956    }
1957    
1958    /**
1959     * Just a convenience wrapper on top of the actual yyAutoComplete()
1960     * implementation. See description above for details.
1961     */
1962    static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack) {
1963        YYStackHistory history;
1964        return yyAutoComplete(stack, history);
1965    }
1966    
1967    namespace LinuxSampler {
1968    
1969    #define DEBUG_SHELL_INTERACTION 0
1970    
1971    /**
1972     * If LSP shell mode is enabled for the respective LSCP client connection, then
1973     * this function is called on every new byte received from that client. It will
1974     * check the current total input line and reply to the LSCP shell for providing
1975     * colored syntax highlighting and potential auto completion in the shell.
1976     *
1977     * It also performs auto correction of obvious & trivial syntax mistakes if
1978     * requested.
1979     *
1980     * The return value of this function will be sent to the client. It contains one
1981     * line specially formatted for the LSCP shell, which can easily be processed by
1982     * the client/shell for gettings its necessary informations like which part of
1983     * the current command line is syntactically correct, which part is incorrect,
1984     * what could be auto completed right now, etc.
1985     *
1986     * @returns LSCP shell response line to be returned to the client
1987     */
1988    String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param) {
1989        // first, determine how many characters (starting from the left) of the
1990        // given input line are already syntactically correct
1991        std::vector<YYTYPE_INT16> stack;
1992        stack.push_back(0); // every Bison symbol stack starts with state zero
1993        String l = line + '\n'; // '\n' to pretend ENTER as if the line was now complete
1994        int n = yyValidCharacters(stack, l, param->bShellAutoCorrect);
1995    
1996        // if auto correction is enabled, apply the auto corrected string to
1997        // intput/output string 'line'
1998        if (param->bShellAutoCorrect) {
1999            int nMin = (n < line.length()) ? n : line.length();
2000            line.replace(0, nMin, l.substr(0, nMin));
2001        }
2002    
2003        // generate an info string that will be sent to the LSCP shell for letting
2004        // it know which part is correct, which one is wrong, where is the cursor, etc.
2005        String result = line;
2006        result.insert(n <= result.length() ? n : result.length(), LSCP_SHK_GOOD_FRONT);
2007        int code = (n > line.length()) ? LSCP_SHU_COMPLETE : (n < line.length()) ?
2008                   LSCP_SHU_SYNTAX_ERR : LSCP_SHU_INCOMPLETE;
2009        result = "SHU:" + ToString(code) + ":" + result + LSCP_SHK_CURSOR;
2010        //if (n > line.length()) result += " [OK]";
2011    
2012        // get a clean parser stack to the last valid parse position
2013        // (due to the appended '\n' character above, and on syntax errors, the
2014        // state stack might be in undesired, i.e. reduced state)
2015        stack.clear();
2016        stack.push_back(0); // every Bison symbol stack starts with state zero
2017        l = line.substr(0, n);
2018        if (!l.empty()) yyValidCharacters(stack, l, param->bShellAutoCorrect);
2019    
2020        // generate auto completion suggestion (based on the current parser stack)
2021        String sSuggestion = yyAutoComplete(stack);
2022        if (!sSuggestion.empty()) result += LSCP_SHK_SUGGEST_BACK + sSuggestion;
2023    
2024    #if DEBUG_SHELL_INTERACTION
2025        printf("%s\n", result.c_str());
2026    #endif
2027    
2028        return result;
2029    }
2030    
2031    /**
2032     * Clears input buffer.
2033   */   */
2034  void restart(yyparse_param_t* pparam, int& yychar) {  void restart(yyparse_param_t* pparam, int& yychar) {
2035      // restart scanner      bytes = 0;
2036      yyrestart(stdin, pparam->pScanner);      ptr   = 0;
2037      // flush input buffer      sLastError = "";
2038      static char buf[1024];      sParsed = "";
2039      while(recv(hSession, buf, 1024, MSG_DONTWAIT) > 0);  }
2040      // reset lookahead symbol  
     yyclearin;  
2041  }  }

Legend:
Removed from v.141  
changed lines
  Added in v.2523

  ViewVC Help
Powered by ViewVC