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

Legend:
Removed from v.159  
changed lines
  Added in v.3054

  ViewVC Help
Powered by ViewVC