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

Legend:
Removed from v.143  
changed lines
  Added in v.2518

  ViewVC Help
Powered by ViewVC