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

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

  ViewVC Help
Powered by ViewVC