/[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 1345 by iliev, Thu Sep 13 21:46:25 2007 UTC revision 2528 by schoenebeck, Mon Mar 3 12:02:40 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 - 2007 Christian Schoenebeck                       *   *   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 34  Line 34 
34  #include "lscpparser.h"  #include "lscpparser.h"
35  #include "lscpserver.h"  #include "lscpserver.h"
36  #include "lscpevent.h"  #include "lscpevent.h"
37    #include "lscpsymbols.h"
38    #include <algorithm>
39    #include "lscp.h"
40    
41    namespace LinuxSampler {
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)  #define SESSION_PARAM ((yyparse_param_t*) yyparse_param)
46  #define INCREMENT_LINE { SESSION_PARAM->iLine++; SESSION_PARAM->iColumn = 0; }  #define INCREMENT_LINE { SESSION_PARAM->iLine++; SESSION_PARAM->iColumn = 0; sParsed.clear(); }
47    
48  // clears input buffer  // 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    
 // we provide our own version of yyerror() so we don't have to link against the yacc library  
 void yyerror(const char* s);  
   
52  static char buf[1024]; // input buffer to feed the parser with new characters  static char buf[1024]; // input buffer to feed the parser with new characters
53  static int bytes = 0;  // current number of characters in the input buffer  static int bytes = 0;  // current number of characters in the input buffer
54  static int ptr   = 0;  // current position in the input buffer  static int ptr   = 0;  // current position in the input buffer
55  static String sLastError; // error message of the last error occured  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  // external reference to the function which actually reads from the socket
59  extern int GetLSCPCommand( void *buf, int max_size);  extern int GetLSCPCommand( void *buf, int max_size);
# Line 64  inline bool isExtendedAsciiChar(const ch Line 67  inline bool isExtendedAsciiChar(const ch
67      return (c < 0);      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  // custom scanner function which reads from the socket
81  // (bison expects it to return the numerical ID of the next  // (bison expects it to return the numerical ID of the next
82  // "recognized token" from the input stream)  // "recognized token" from the input stream)
# Line 81  int yylex(YYSTYPE* yylval) { Line 94  int yylex(YYSTYPE* yylval) {
94      const char c = buf[ptr++];      const char c = buf[ptr++];
95      // increment current reading position (just for verbosity / messages)      // increment current reading position (just for verbosity / messages)
96      GetCurrentYaccSession()->iColumn++;      GetCurrentYaccSession()->iColumn++;
97        sParsed += c;
98      // we have to handle "normal" and "extended" ASCII characters separately      // we have to handle "normal" and "extended" ASCII characters separately
99      if (isExtendedAsciiChar(c)) {      if (isExtendedAsciiChar(c)) {
100          // workaround for characters with ASCII code higher than 127          // workaround for characters with ASCII code higher than 127
# Line 101  int octalsToNumber(char oct_digit0, char Line 115  int octalsToNumber(char oct_digit0, char
115      return atoi(d2)*8*8 + atoi(d1)*8 + atoi(d0);      return atoi(d2)*8*8 + atoi(d1)*8 + atoi(d0);
116  }  }
117    
 int hexToNumber(char hex_digit) {  
     switch (hex_digit) {  
         case '0': return 0;  
         case '1': return 1;  
         case '2': return 2;  
         case '3': return 3;  
         case '4': return 4;  
         case '5': return 5;  
         case '6': return 6;  
         case '7': return 7;  
         case '8': return 8;  
         case '9': return 9;  
         // grammar rule 'digit_hex' already forced lower case  
         case 'a': return 10;  
         case 'b': return 11;  
         case 'c': return 12;  
         case 'd': return 13;  
         case 'e': return 14;  
         case 'f': return 15;  
         default:  return 0;  
     }  
118  }  }
119    
120  int hexsToNumber(char hex_digit0, char hex_digit1 = '0') {  using namespace LinuxSampler;
121      return hexToNumber(hex_digit1)*16 + hexToNumber(hex_digit0);  
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        // get the text part already parsed (of current line)
134        const bool bContainsLineFeed =
135            sParsed.find('\r') != std::string::npos ||
136            sParsed.find('\n') != std::string::npos;
137        // remove potential line feed characters
138        if (bContainsLineFeed) {
139            for (size_t p = sParsed.find('\r'); p != std::string::npos;
140                 p = sParsed.find('\r')) sParsed.erase(p);
141            for (size_t p = sParsed.find('\n'); p != std::string::npos;
142                 p = sParsed.find('\n')) sParsed.erase(p);
143        }
144    
145        // start assembling the error message with Bison's own message
146        String txt = s;
147    
148        // append exact position info of syntax error
149        txt += (" (line:"  + ToString(param->iLine+1)) +
150               (",column:" + ToString(param->iColumn)) + ")";
151    
152        // append the part of the lined that has already been parsed
153        txt += ". Context: \"" + sParsed;
154        if (txt.empty() || bContainsLineFeed)
155            txt += "^";
156        else
157            txt.insert(txt.size() - 1, "^");
158        txt += "...\"";
159    
160        // append the non-terminal symbols expected now/next
161        std::set<String> expectedSymbols = yyExpectedSymbols();
162        for (std::set<String>::const_iterator it = expectedSymbols.begin();
163             it != expectedSymbols.end(); ++it)
164        {
165            if (it == expectedSymbols.begin())
166                txt += " -> Should be: " + *it;
167            else
168                txt += " | " + *it;
169        }
170    
171        dmsg(2,("LSCPParser: %s\n", txt.c_str()));
172        sLastError = txt;
173  }  }
174    
175  %}  %}
176    
177  // reentrant parser  // reentrant parser
178  %pure_parser  %pure-parser
179    
180    %parse-param {void* yyparse_param}
181    
182    // After entering the yyparse() function, store references to the parser's
183    // symbol stack, so that we can create more helpful syntax error messages than
184    // Bison (2.x) could do.
185    %initial-action {
186        yyparse_param_t* p = (yyparse_param_t*) yyparse_param;
187        p->ppStackBottom = &yyss;
188        p->ppStackTop    = &yyssp;
189    }
190    
191  // tell bison to spit out verbose syntax error messages  // tell bison to spit out verbose syntax error messages
192  %error-verbose  %error-verbose
193    
194  %token <Char> EXT_ASCII_CHAR  %token <Char> EXT_ASCII_CHAR
195    
196  %type <Char> char char_base digit digit_oct digit_hex escape_seq escape_seq_octal escape_seq_hex  %type <Char> char char_base alpha_char digit digit_oct digit_hex escape_seq escape_seq_octal escape_seq_hex
197  %type <Dotnum> dotnum volume_value boolean  %type <Dotnum> real dotnum volume_value boolean control_value
198  %type <Number> number sampler_channel instrument_index fx_send_id audio_channel_index device_index midi_input_channel_index midi_input_port_index midi_map midi_bank midi_prog midi_ctrl  %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  %type <String> string string_escaped text text_escaped textval_escaped stringval stringval_escaped digits param_val_list param_val query_val filename db_path map_name entry_name fx_send_name engine_name command add_instruction create_instruction destroy_instruction get_instruction list_instruction load_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  %type <String> string string_escaped text text_escaped text_escaped_base stringval stringval_escaped digits param_val_list param_val query_val filename module effect_system db_path map_name entry_name fx_send_name effect_name engine_name line statement command add_instruction create_instruction destroy_instruction get_instruction list_instruction load_instruction send_instruction set_chan_instruction load_instr_args load_engine_args audio_output_type_name midi_input_type_name remove_instruction unmap_instruction set_instruction subscribe_event unsubscribe_event map_instruction reset_instruction clear_instruction find_instruction move_instruction copy_instruction scan_mode edit_instruction format_instruction append_instruction insert_instruction
200  %type <FillResponse> buffer_size_type  %type <FillResponse> buffer_size_type
201  %type <KeyValList> key_val_list query_val_list  %type <KeyValList> key_val_list query_val_list
202  %type <LoadMode> instr_load_mode  %type <LoadMode> instr_load_mode
203  %type <Bool> modal_arg  %type <Bool> modal_arg
204  %type <UniversalPath> path path_base  %type <UniversalPath> path path_base path_prefix path_body
205    
206  %start input  %start input
207    
# Line 163  int hexsToNumber(char hex_digit0, char h Line 218  int hexsToNumber(char hex_digit0, char h
218    
219  // GRAMMAR_BNF_BEGIN - do NOT delete or modify this line !!!  // GRAMMAR_BNF_BEGIN - do NOT delete or modify this line !!!
220    
221  input                 : line LF  input                 :  line   { INCREMENT_LINE; if (!$1.empty()) LSCPSERVER->AnswerClient($1); return LSCP_DONE; }
222                        | line CR LF                        |  error  { INCREMENT_LINE; LSCPSERVER->AnswerClient("ERR:0:" + sLastError + "\r\n"); RESTART; return LSCP_SYNTAX_ERROR; }
223                          ;
224    
225    line                  :  statement LF     { $$ = $1; }
226                          |  statement CR LF  { $$ = $1; }
227                        ;                        ;
228    
229  line                  :  /* epsilon (empty line ignored) */ { INCREMENT_LINE; return LSCP_DONE; }  statement             :  /* epsilon (empty statement/line ignored) */  { $$ = ""; }
230                        |  comment  { INCREMENT_LINE; return LSCP_DONE; }                        |  comment  { $$ = ""; }
231                        |  command  { INCREMENT_LINE; LSCPSERVER->AnswerClient($1); return LSCP_DONE; }                        |  command
                       |  error    { INCREMENT_LINE; LSCPSERVER->AnswerClient("ERR:0:" + sLastError + "\r\n"); RESTART; return LSCP_SYNTAX_ERROR; }  
232                        ;                        ;
233    
234  comment               :  '#'  comment               :  '#'
# Line 198  command               :  ADD SP add_inst Line 256  command               :  ADD SP add_inst
256                        |  MOVE SP move_instruction              { $$ = $3;                                                }                        |  MOVE SP move_instruction              { $$ = $3;                                                }
257                        |  COPY SP copy_instruction              { $$ = $3;                                                }                        |  COPY SP copy_instruction              { $$ = $3;                                                }
258                        |  EDIT SP edit_instruction              { $$ = $3;                                                }                        |  EDIT SP edit_instruction              { $$ = $3;                                                }
259                          |  FORMAT SP format_instruction          { $$ = $3;                                                }
260                          |  SEND SP send_instruction              { $$ = $3;                                                }
261                          |  APPEND SP append_instruction          { $$ = $3;                                                }
262                          |  INSERT SP insert_instruction          { $$ = $3;                                                }
263                        |  RESET                                 { $$ = LSCPSERVER->ResetSampler();                        }                        |  RESET                                 { $$ = LSCPSERVER->ResetSampler();                        }
264                        |  QUIT                                  { LSCPSERVER->AnswerClient("Bye!\r\n"); return LSCP_QUIT; }                        |  QUIT                                  { LSCPSERVER->AnswerClient("Bye!\r\n"); return LSCP_QUIT; }
265                        ;                        ;
266    
267  add_instruction       :  CHANNEL                               { $$ = LSCPSERVER->AddChannel();                  }  add_instruction       :  CHANNEL                               { $$ = LSCPSERVER->AddChannel();                  }
268                          |  CHANNEL SP MIDI_INPUT SP sampler_channel SP device_index                           { $$ = LSCPSERVER->AddChannelMidiInput($5,$7);    }
269                          |  CHANNEL SP MIDI_INPUT SP sampler_channel SP device_index SP midi_input_port_index  { $$ = LSCPSERVER->AddChannelMidiInput($5,$7,$9); }
270                        |  DB_INSTRUMENT_DIRECTORY SP db_path    { $$ = LSCPSERVER->AddDbInstrumentDirectory($3);  }                        |  DB_INSTRUMENT_DIRECTORY SP db_path    { $$ = LSCPSERVER->AddDbInstrumentDirectory($3);  }
271                        |  DB_INSTRUMENTS SP NON_MODAL SP scan_mode SP db_path SP filename         { $$ = LSCPSERVER->AddDbInstruments($5,$7,$9, true);  }                        |  DB_INSTRUMENTS SP NON_MODAL SP scan_mode SP db_path SP filename                        { $$ = LSCPSERVER->AddDbInstruments($5,$7,$9, true);        }
272                        |  DB_INSTRUMENTS SP scan_mode SP db_path SP filename                      { $$ = LSCPSERVER->AddDbInstruments($3,$5,$7);        }                        |  DB_INSTRUMENTS SP NON_MODAL SP scan_mode SP FILE_AS_DIR SP db_path SP filename         { $$ = LSCPSERVER->AddDbInstruments($5,$9,$11, true, true); }
273                        |  DB_INSTRUMENTS SP NON_MODAL SP db_path SP filename                      { $$ = LSCPSERVER->AddDbInstruments($5,$7, -1, true); }                        |  DB_INSTRUMENTS SP scan_mode SP db_path SP filename                                     { $$ = LSCPSERVER->AddDbInstruments($3,$5,$7);              }
274                        |  DB_INSTRUMENTS SP NON_MODAL SP db_path SP filename SP instrument_index  { $$ = LSCPSERVER->AddDbInstruments($5,$7,$9, true);  }                        |  DB_INSTRUMENTS SP scan_mode SP FILE_AS_DIR SP db_path SP filename                      { $$ = LSCPSERVER->AddDbInstruments($3,$7,$9, false, true); }
275                        |  DB_INSTRUMENTS SP db_path SP filename                                   { $$ = LSCPSERVER->AddDbInstruments($3,$5);           }                        |  DB_INSTRUMENTS SP NON_MODAL SP db_path SP filename                                     { $$ = LSCPSERVER->AddDbInstruments($5,$7, -1, true);       }
276                        |  DB_INSTRUMENTS SP db_path SP filename SP instrument_index               { $$ = LSCPSERVER->AddDbInstruments($3,$5,$7);        }                        |  DB_INSTRUMENTS SP NON_MODAL SP db_path SP filename SP instrument_index                 { $$ = LSCPSERVER->AddDbInstruments($5,$7,$9, true);        }
277                          |  DB_INSTRUMENTS SP db_path SP filename                                                  { $$ = LSCPSERVER->AddDbInstruments($3,$5);                 }
278                          |  DB_INSTRUMENTS SP db_path SP filename SP instrument_index                              { $$ = LSCPSERVER->AddDbInstruments($3,$5,$7);              }
279                        |  MIDI_INSTRUMENT_MAP                   { $$ = LSCPSERVER->AddMidiInstrumentMap();                }                        |  MIDI_INSTRUMENT_MAP                   { $$ = LSCPSERVER->AddMidiInstrumentMap();                }
280                        |  MIDI_INSTRUMENT_MAP SP map_name       { $$ = LSCPSERVER->AddMidiInstrumentMap($3);              }                        |  MIDI_INSTRUMENT_MAP SP map_name       { $$ = LSCPSERVER->AddMidiInstrumentMap($3);              }
281                          |  SEND_EFFECT_CHAIN SP device_index     { $$ = LSCPSERVER->AddSendEffectChain($3);                }
282                        ;                        ;
283    
284  subscribe_event       :  AUDIO_OUTPUT_DEVICE_COUNT             { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_audio_device_count);   }  subscribe_event       :  AUDIO_OUTPUT_DEVICE_COUNT             { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_audio_device_count);   }
# Line 219  subscribe_event       :  AUDIO_OUTPUT_DE Line 286  subscribe_event       :  AUDIO_OUTPUT_DE
286                        |  MIDI_INPUT_DEVICE_COUNT               { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_midi_device_count);    }                        |  MIDI_INPUT_DEVICE_COUNT               { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_midi_device_count);    }
287                        |  MIDI_INPUT_DEVICE_INFO                { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_midi_device_info);     }                        |  MIDI_INPUT_DEVICE_INFO                { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_midi_device_info);     }
288                        |  CHANNEL_COUNT                         { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_channel_count);        }                        |  CHANNEL_COUNT                         { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_channel_count);        }
289                          |  CHANNEL_MIDI                          { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_channel_midi);         }
290                          |  DEVICE_MIDI                           { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_device_midi);          }
291                        |  VOICE_COUNT                           { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_voice_count);          }                        |  VOICE_COUNT                           { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_voice_count);          }
292                        |  STREAM_COUNT                          { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_stream_count);         }                        |  STREAM_COUNT                          { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_stream_count);         }
293                        |  BUFFER_FILL                           { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_buffer_fill);          }                        |  BUFFER_FILL                           { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_buffer_fill);          }
# Line 235  subscribe_event       :  AUDIO_OUTPUT_DE Line 304  subscribe_event       :  AUDIO_OUTPUT_DE
304                        |  DB_INSTRUMENT_INFO                    { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_db_instr_info);        }                        |  DB_INSTRUMENT_INFO                    { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_db_instr_info);        }
305                        |  DB_INSTRUMENTS_JOB_INFO               { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_db_instrs_job_info);   }                        |  DB_INSTRUMENTS_JOB_INFO               { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_db_instrs_job_info);   }
306                        |  MISCELLANEOUS                         { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_misc);                 }                        |  MISCELLANEOUS                         { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_misc);                 }
307                          |  TOTAL_STREAM_COUNT                    { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_total_stream_count);   }
308                        |  TOTAL_VOICE_COUNT                     { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_total_voice_count);    }                        |  TOTAL_VOICE_COUNT                     { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_total_voice_count);    }
309                        |  GLOBAL_INFO                           { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_global_info);          }                        |  GLOBAL_INFO                           { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_global_info);          }
310                          |  EFFECT_INSTANCE_COUNT                 { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_fx_instance_count);    }
311                          |  EFFECT_INSTANCE_INFO                  { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_fx_instance_info);     }
312                          |  SEND_EFFECT_CHAIN_COUNT               { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_send_fx_chain_count);  }
313                          |  SEND_EFFECT_CHAIN_INFO                { $$ = LSCPSERVER->SubscribeNotification(LSCPEvent::event_send_fx_chain_info);   }
314                        ;                        ;
315    
316  unsubscribe_event     :  AUDIO_OUTPUT_DEVICE_COUNT             { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_audio_device_count);   }  unsubscribe_event     :  AUDIO_OUTPUT_DEVICE_COUNT             { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_audio_device_count);   }
# Line 244  unsubscribe_event     :  AUDIO_OUTPUT_DE Line 318  unsubscribe_event     :  AUDIO_OUTPUT_DE
318                        |  MIDI_INPUT_DEVICE_COUNT               { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_midi_device_count);    }                        |  MIDI_INPUT_DEVICE_COUNT               { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_midi_device_count);    }
319                        |  MIDI_INPUT_DEVICE_INFO                { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_midi_device_info);     }                        |  MIDI_INPUT_DEVICE_INFO                { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_midi_device_info);     }
320                        |  CHANNEL_COUNT                         { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_channel_count);        }                        |  CHANNEL_COUNT                         { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_channel_count);        }
321                          |  CHANNEL_MIDI                          { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_channel_midi);         }
322                          |  DEVICE_MIDI                           { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_device_midi);          }
323                        |  VOICE_COUNT                           { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_voice_count);          }                        |  VOICE_COUNT                           { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_voice_count);          }
324                        |  STREAM_COUNT                          { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_stream_count);         }                        |  STREAM_COUNT                          { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_stream_count);         }
325                        |  BUFFER_FILL                           { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_buffer_fill);          }                        |  BUFFER_FILL                           { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_buffer_fill);          }
# Line 260  unsubscribe_event     :  AUDIO_OUTPUT_DE Line 336  unsubscribe_event     :  AUDIO_OUTPUT_DE
336                        |  DB_INSTRUMENT_INFO                    { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_db_instr_info);        }                        |  DB_INSTRUMENT_INFO                    { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_db_instr_info);        }
337                        |  DB_INSTRUMENTS_JOB_INFO               { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_db_instrs_job_info);   }                        |  DB_INSTRUMENTS_JOB_INFO               { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_db_instrs_job_info);   }
338                        |  MISCELLANEOUS                         { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_misc);                 }                        |  MISCELLANEOUS                         { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_misc);                 }
339                          |  TOTAL_STREAM_COUNT                    { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_total_stream_count);   }
340                        |  TOTAL_VOICE_COUNT                     { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_total_voice_count);    }                        |  TOTAL_VOICE_COUNT                     { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_total_voice_count);    }
341                        |  GLOBAL_INFO                           { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_global_info);          }                        |  GLOBAL_INFO                           { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_global_info);          }
342                          |  EFFECT_INSTANCE_COUNT                 { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_fx_instance_count);    }
343                          |  EFFECT_INSTANCE_INFO                  { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_fx_instance_info);     }
344                          |  SEND_EFFECT_CHAIN_COUNT               { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_send_fx_chain_count);  }
345                          |  SEND_EFFECT_CHAIN_INFO                { $$ = LSCPSERVER->UnsubscribeNotification(LSCPEvent::event_send_fx_chain_info);   }
346                        ;                        ;
347    
348  map_instruction       :  MIDI_INSTRUMENT SP modal_arg midi_map SP midi_bank SP midi_prog SP engine_name SP filename SP instrument_index SP volume_value { $$ = LSCPSERVER->AddOrReplaceMIDIInstrumentMapping($4,$6,$8,$10,$12,$14,$16,MidiInstrumentMapper::VOID,"",$3); }  map_instruction       :  MIDI_INSTRUMENT SP modal_arg midi_map SP midi_bank SP midi_prog SP engine_name SP filename SP instrument_index SP volume_value { $$ = LSCPSERVER->AddOrReplaceMIDIInstrumentMapping($4,$6,$8,$10,$12,$14,$16,MidiInstrumentMapper::DONTCARE,"",$3); }
349                        |  MIDI_INSTRUMENT SP modal_arg midi_map SP midi_bank SP midi_prog SP engine_name SP filename SP instrument_index SP volume_value SP instr_load_mode { $$ = LSCPSERVER->AddOrReplaceMIDIInstrumentMapping($4,$6,$8,$10,$12,$14,$16,$18,"",$3); }                        |  MIDI_INSTRUMENT SP modal_arg midi_map SP midi_bank SP midi_prog SP engine_name SP filename SP instrument_index SP volume_value SP instr_load_mode { $$ = LSCPSERVER->AddOrReplaceMIDIInstrumentMapping($4,$6,$8,$10,$12,$14,$16,$18,"",$3); }
350                        |  MIDI_INSTRUMENT SP modal_arg midi_map SP midi_bank SP midi_prog SP engine_name SP filename SP instrument_index SP volume_value SP entry_name { $$ = LSCPSERVER->AddOrReplaceMIDIInstrumentMapping($4,$6,$8,$10,$12,$14,$16,MidiInstrumentMapper::VOID,$18,$3); }                        |  MIDI_INSTRUMENT SP modal_arg midi_map SP midi_bank SP midi_prog SP engine_name SP filename SP instrument_index SP volume_value SP entry_name { $$ = LSCPSERVER->AddOrReplaceMIDIInstrumentMapping($4,$6,$8,$10,$12,$14,$16,MidiInstrumentMapper::DONTCARE,$18,$3); }
351                        |  MIDI_INSTRUMENT SP modal_arg midi_map SP midi_bank SP midi_prog SP engine_name SP filename SP instrument_index SP volume_value SP instr_load_mode SP entry_name { $$ = LSCPSERVER->AddOrReplaceMIDIInstrumentMapping($4,$6,$8,$10,$12,$14,$16,$18,$20,$3); }                        |  MIDI_INSTRUMENT SP modal_arg midi_map SP midi_bank SP midi_prog SP engine_name SP filename SP instrument_index SP volume_value SP instr_load_mode SP entry_name { $$ = LSCPSERVER->AddOrReplaceMIDIInstrumentMapping($4,$6,$8,$10,$12,$14,$16,$18,$20,$3); }
352                        ;                        ;
353    
# Line 274  unmap_instruction     :  MIDI_INSTRUMENT Line 355  unmap_instruction     :  MIDI_INSTRUMENT
355                        ;                        ;
356    
357  remove_instruction    :  CHANNEL SP sampler_channel                   { $$ = LSCPSERVER->RemoveChannel($3);                      }  remove_instruction    :  CHANNEL SP sampler_channel                   { $$ = LSCPSERVER->RemoveChannel($3);                      }
358                          |  CHANNEL SP MIDI_INPUT SP sampler_channel                                           { $$ = LSCPSERVER->RemoveChannelMidiInput($5);       }
359                          |  CHANNEL SP MIDI_INPUT SP sampler_channel SP device_index                           { $$ = LSCPSERVER->RemoveChannelMidiInput($5,$7);    }
360                          |  CHANNEL SP MIDI_INPUT SP sampler_channel SP device_index SP midi_input_port_index  { $$ = LSCPSERVER->RemoveChannelMidiInput($5,$7,$9); }
361                        |  MIDI_INSTRUMENT_MAP SP midi_map              { $$ = LSCPSERVER->RemoveMidiInstrumentMap($3);            }                        |  MIDI_INSTRUMENT_MAP SP midi_map              { $$ = LSCPSERVER->RemoveMidiInstrumentMap($3);            }
362                        |  MIDI_INSTRUMENT_MAP SP ALL                   { $$ = LSCPSERVER->RemoveAllMidiInstrumentMaps();          }                        |  MIDI_INSTRUMENT_MAP SP ALL                   { $$ = LSCPSERVER->RemoveAllMidiInstrumentMaps();          }
363                          |  SEND_EFFECT_CHAIN SP device_index SP effect_chain  { $$ = LSCPSERVER->RemoveSendEffectChain($3,$5);     }
364                          |  SEND_EFFECT_CHAIN SP EFFECT SP device_index SP effect_chain SP chain_pos  { $$ = LSCPSERVER->RemoveSendEffectChainEffect($5,$7,$9); }
365                          |  FX_SEND SP EFFECT SP sampler_channel SP fx_send_id  { $$ = LSCPSERVER->SetFxSendEffect($5,$7,-1,-1);    }
366                        |  DB_INSTRUMENT_DIRECTORY SP FORCE SP db_path  { $$ = LSCPSERVER->RemoveDbInstrumentDirectory($5, true);  }                        |  DB_INSTRUMENT_DIRECTORY SP FORCE SP db_path  { $$ = LSCPSERVER->RemoveDbInstrumentDirectory($5, true);  }
367                        |  DB_INSTRUMENT_DIRECTORY SP db_path           { $$ = LSCPSERVER->RemoveDbInstrumentDirectory($3);        }                        |  DB_INSTRUMENT_DIRECTORY SP db_path           { $$ = LSCPSERVER->RemoveDbInstrumentDirectory($3);        }
368                        |  DB_INSTRUMENT SP db_path                     { $$ = LSCPSERVER->RemoveDbInstrument($3);                 }                        |  DB_INSTRUMENT SP db_path                     { $$ = LSCPSERVER->RemoveDbInstrument($3);                 }
369                        ;                        ;
370    
371  get_instruction       :  AVAILABLE_ENGINES                                                          { $$ = LSCPSERVER->GetAvailableEngines();                          }  get_instruction       :  AVAILABLE_ENGINES                                                          { $$ = LSCPSERVER->GetAvailableEngines();                          }
372                          |  AVAILABLE_EFFECTS                                                          { $$ = LSCPSERVER->GetAvailableEffects();                          }
373                          |  EFFECT_INSTANCES                                                           { $$ = LSCPSERVER->GetEffectInstances();                           }
374                          |  EFFECT SP INFO SP effect_index                                             { $$ = LSCPSERVER->GetEffectInfo($5);                              }
375                          |  EFFECT_INSTANCE SP INFO SP effect_instance                                 { $$ = LSCPSERVER->GetEffectInstanceInfo($5);                      }
376                          |  EFFECT_INSTANCE_INPUT_CONTROL SP INFO SP effect_instance SP input_control  { $$ = LSCPSERVER->GetEffectInstanceInputControlInfo($5,$7);       }
377                          |  SEND_EFFECT_CHAINS SP device_index                                         { $$ = LSCPSERVER->GetSendEffectChains($3);                        }
378                          |  SEND_EFFECT_CHAIN SP INFO SP device_index SP effect_chain                  { $$ = LSCPSERVER->GetSendEffectChainInfo($5,$7);                  }
379                        |  AVAILABLE_MIDI_INPUT_DRIVERS                                               { $$ = LSCPSERVER->GetAvailableMidiInputDrivers();                 }                        |  AVAILABLE_MIDI_INPUT_DRIVERS                                               { $$ = LSCPSERVER->GetAvailableMidiInputDrivers();                 }
380                        |  MIDI_INPUT_DRIVER SP INFO SP string                                        { $$ = LSCPSERVER->GetMidiInputDriverInfo($5);                     }                        |  MIDI_INPUT_DRIVER SP INFO SP string                                        { $$ = LSCPSERVER->GetMidiInputDriverInfo($5);                     }
381                        |  MIDI_INPUT_DRIVER_PARAMETER SP INFO SP string SP string                    { $$ = LSCPSERVER->GetMidiInputDriverParameterInfo($5, $7);        }                        |  MIDI_INPUT_DRIVER_PARAMETER SP INFO SP string SP string                    { $$ = LSCPSERVER->GetMidiInputDriverParameterInfo($5, $7);        }
# Line 305  get_instruction       :  AVAILABLE_ENGIN Line 399  get_instruction       :  AVAILABLE_ENGIN
399                        |  CHANNEL SP VOICE_COUNT SP sampler_channel                                  { $$ = LSCPSERVER->GetVoiceCount($5);                              }                        |  CHANNEL SP VOICE_COUNT SP sampler_channel                                  { $$ = LSCPSERVER->GetVoiceCount($5);                              }
400                        |  ENGINE SP INFO SP engine_name                                              { $$ = LSCPSERVER->GetEngineInfo($5);                              }                        |  ENGINE SP INFO SP engine_name                                              { $$ = LSCPSERVER->GetEngineInfo($5);                              }
401                        |  SERVER SP INFO                                                             { $$ = LSCPSERVER->GetServerInfo();                                }                        |  SERVER SP INFO                                                             { $$ = LSCPSERVER->GetServerInfo();                                }
402                          |  TOTAL_STREAM_COUNT                                                         { $$ = LSCPSERVER->GetTotalStreamCount();                           }
403                        |  TOTAL_VOICE_COUNT                                                          { $$ = LSCPSERVER->GetTotalVoiceCount();                           }                        |  TOTAL_VOICE_COUNT                                                          { $$ = LSCPSERVER->GetTotalVoiceCount();                           }
404                        |  TOTAL_VOICE_COUNT_MAX                                                      { $$ = LSCPSERVER->GetTotalVoiceCountMax();                        }                        |  TOTAL_VOICE_COUNT_MAX                                                      { $$ = LSCPSERVER->GetTotalVoiceCountMax();                        }
405                        |  MIDI_INSTRUMENTS SP midi_map                                               { $$ = LSCPSERVER->GetMidiInstrumentMappings($3);                  }                        |  MIDI_INSTRUMENTS SP midi_map                                               { $$ = LSCPSERVER->GetMidiInstrumentMappings($3);                  }
# Line 322  get_instruction       :  AVAILABLE_ENGIN Line 417  get_instruction       :  AVAILABLE_ENGIN
417                        |  DB_INSTRUMENT SP INFO SP db_path                                           { $$ = LSCPSERVER->GetDbInstrumentInfo($5);                        }                        |  DB_INSTRUMENT SP INFO SP db_path                                           { $$ = LSCPSERVER->GetDbInstrumentInfo($5);                        }
418                        |  DB_INSTRUMENTS_JOB SP INFO SP number                                       { $$ = LSCPSERVER->GetDbInstrumentsJobInfo($5);                    }                        |  DB_INSTRUMENTS_JOB SP INFO SP number                                       { $$ = LSCPSERVER->GetDbInstrumentsJobInfo($5);                    }
419                        |  VOLUME                                                                     { $$ = LSCPSERVER->GetGlobalVolume();                              }                        |  VOLUME                                                                     { $$ = LSCPSERVER->GetGlobalVolume();                              }
420                          |  VOICES                                                                     { $$ = LSCPSERVER->GetGlobalMaxVoices();                           }
421                          |  STREAMS                                                                    { $$ = LSCPSERVER->GetGlobalMaxStreams();                          }
422                          |  FILE SP INSTRUMENTS SP filename                                            { $$ = LSCPSERVER->GetFileInstruments($5);                         }
423                          |  FILE SP INSTRUMENT SP INFO SP filename SP instrument_index                 { $$ = LSCPSERVER->GetFileInstrumentInfo($7,$9);                   }
424                        ;                        ;
425    
426  set_instruction       :  AUDIO_OUTPUT_DEVICE_PARAMETER SP number SP string '=' param_val_list             { $$ = LSCPSERVER->SetAudioOutputDeviceParameter($3, $5, $7);      }  set_instruction       :  AUDIO_OUTPUT_DEVICE_PARAMETER SP number SP string '=' param_val_list             { $$ = LSCPSERVER->SetAudioOutputDeviceParameter($3, $5, $7);      }
# Line 329  set_instruction       :  AUDIO_OUTPUT_DE Line 428  set_instruction       :  AUDIO_OUTPUT_DE
428                        |  MIDI_INPUT_DEVICE_PARAMETER SP number SP string '=' param_val_list               { $$ = LSCPSERVER->SetMidiInputDeviceParameter($3, $5, $7);        }                        |  MIDI_INPUT_DEVICE_PARAMETER SP number SP string '=' param_val_list               { $$ = LSCPSERVER->SetMidiInputDeviceParameter($3, $5, $7);        }
429                        |  MIDI_INPUT_PORT_PARAMETER SP number SP number SP string '=' NONE                 { $$ = LSCPSERVER->SetMidiInputPortParameter($3, $5, $7, "");      }                        |  MIDI_INPUT_PORT_PARAMETER SP number SP number SP string '=' NONE                 { $$ = LSCPSERVER->SetMidiInputPortParameter($3, $5, $7, "");      }
430                        |  MIDI_INPUT_PORT_PARAMETER SP number SP number SP string '=' param_val_list       { $$ = LSCPSERVER->SetMidiInputPortParameter($3, $5, $7, $9);      }                        |  MIDI_INPUT_PORT_PARAMETER SP number SP number SP string '=' param_val_list       { $$ = LSCPSERVER->SetMidiInputPortParameter($3, $5, $7, $9);      }
431                          |  EFFECT_INSTANCE_INPUT_CONTROL SP VALUE SP effect_instance SP input_control SP control_value  { $$ = LSCPSERVER->SetEffectInstanceInputControlValue($5, $7, $9); }
432                        |  CHANNEL SP set_chan_instruction                                                  { $$ = $3;                                                         }                        |  CHANNEL SP set_chan_instruction                                                  { $$ = $3;                                                         }
433                        |  MIDI_INSTRUMENT_MAP SP NAME SP midi_map SP map_name                              { $$ = LSCPSERVER->SetMidiInstrumentMapName($5, $7);               }                        |  MIDI_INSTRUMENT_MAP SP NAME SP midi_map SP map_name                              { $$ = LSCPSERVER->SetMidiInstrumentMapName($5, $7);               }
434                        |  FX_SEND SP NAME SP sampler_channel SP fx_send_id SP fx_send_name                 { $$ = LSCPSERVER->SetFxSendName($5,$7,$9);                        }                        |  FX_SEND SP NAME SP sampler_channel SP fx_send_id SP fx_send_name                 { $$ = LSCPSERVER->SetFxSendName($5,$7,$9);                        }
435                        |  FX_SEND SP AUDIO_OUTPUT_CHANNEL SP sampler_channel SP fx_send_id SP audio_channel_index SP audio_channel_index  { $$ = LSCPSERVER->SetFxSendAudioOutputChannel($5,$7,$9,$11); }                        |  FX_SEND SP AUDIO_OUTPUT_CHANNEL SP sampler_channel SP fx_send_id SP audio_channel_index SP audio_channel_index  { $$ = LSCPSERVER->SetFxSendAudioOutputChannel($5,$7,$9,$11); }
436                        |  FX_SEND SP MIDI_CONTROLLER SP sampler_channel SP fx_send_id SP midi_ctrl         { $$ = LSCPSERVER->SetFxSendMidiController($5,$7,$9);              }                        |  FX_SEND SP MIDI_CONTROLLER SP sampler_channel SP fx_send_id SP midi_ctrl         { $$ = LSCPSERVER->SetFxSendMidiController($5,$7,$9);              }
437                        |  FX_SEND SP LEVEL SP sampler_channel SP fx_send_id SP volume_value                { $$ = LSCPSERVER->SetFxSendLevel($5,$7,$9);                       }                        |  FX_SEND SP LEVEL SP sampler_channel SP fx_send_id SP volume_value                { $$ = LSCPSERVER->SetFxSendLevel($5,$7,$9);                       }
438                          |  FX_SEND SP EFFECT SP sampler_channel SP fx_send_id SP effect_chain SP chain_pos  { $$ = LSCPSERVER->SetFxSendEffect($5,$7,$9,$11);                  }
439                        |  DB_INSTRUMENT_DIRECTORY SP NAME SP db_path SP stringval_escaped                  { $$ = LSCPSERVER->SetDbInstrumentDirectoryName($5,$7);            }                        |  DB_INSTRUMENT_DIRECTORY SP NAME SP db_path SP stringval_escaped                  { $$ = LSCPSERVER->SetDbInstrumentDirectoryName($5,$7);            }
440                        |  DB_INSTRUMENT_DIRECTORY SP DESCRIPTION SP db_path SP stringval_escaped           { $$ = LSCPSERVER->SetDbInstrumentDirectoryDescription($5,$7);     }                        |  DB_INSTRUMENT_DIRECTORY SP DESCRIPTION SP db_path SP stringval_escaped           { $$ = LSCPSERVER->SetDbInstrumentDirectoryDescription($5,$7);     }
441                        |  DB_INSTRUMENT SP NAME SP db_path SP stringval_escaped                            { $$ = LSCPSERVER->SetDbInstrumentName($5,$7);                     }                        |  DB_INSTRUMENT SP NAME SP db_path SP stringval_escaped                            { $$ = LSCPSERVER->SetDbInstrumentName($5,$7);                     }
442                        |  DB_INSTRUMENT SP DESCRIPTION SP db_path SP stringval_escaped                     { $$ = LSCPSERVER->SetDbInstrumentDescription($5,$7);              }                        |  DB_INSTRUMENT SP DESCRIPTION SP db_path SP stringval_escaped                     { $$ = LSCPSERVER->SetDbInstrumentDescription($5,$7);              }
443                          |  DB_INSTRUMENT SP FILE_PATH SP filename SP filename                               { $$ = LSCPSERVER->SetDbInstrumentFilePath($5,$7);                 }
444                        |  ECHO SP boolean                                                                  { $$ = LSCPSERVER->SetEcho((yyparse_param_t*) yyparse_param, $3);  }                        |  ECHO SP boolean                                                                  { $$ = LSCPSERVER->SetEcho((yyparse_param_t*) yyparse_param, $3);  }
445                          |  SHELL SP INTERACT SP boolean                                                     { $$ = LSCPSERVER->SetShellInteract((yyparse_param_t*) yyparse_param, $5); }
446                          |  SHELL SP AUTO_CORRECT SP boolean                                                 { $$ = LSCPSERVER->SetShellAutoCorrect((yyparse_param_t*) yyparse_param, $5); }
447                        |  VOLUME SP volume_value                                                           { $$ = LSCPSERVER->SetGlobalVolume($3);                            }                        |  VOLUME SP volume_value                                                           { $$ = LSCPSERVER->SetGlobalVolume($3);                            }
448                          |  VOICES SP number                                                                 { $$ = LSCPSERVER->SetGlobalMaxVoices($3);                         }
449                          |  STREAMS SP number                                                                { $$ = LSCPSERVER->SetGlobalMaxStreams($3);                        }
450                        ;                        ;
451    
452  create_instruction    :  AUDIO_OUTPUT_DEVICE SP string SP key_val_list  { $$ = LSCPSERVER->CreateAudioOutputDevice($3,$5); }  create_instruction    :  AUDIO_OUTPUT_DEVICE SP string SP key_val_list  { $$ = LSCPSERVER->CreateAudioOutputDevice($3,$5); }
# Line 349  create_instruction    :  AUDIO_OUTPUT_DE Line 455  create_instruction    :  AUDIO_OUTPUT_DE
455                        |  MIDI_INPUT_DEVICE SP string                    { $$ = LSCPSERVER->CreateMidiInputDevice($3);      }                        |  MIDI_INPUT_DEVICE SP string                    { $$ = LSCPSERVER->CreateMidiInputDevice($3);      }
456                        |  FX_SEND SP sampler_channel SP midi_ctrl        { $$ = LSCPSERVER->CreateFxSend($3,$5);            }                        |  FX_SEND SP sampler_channel SP midi_ctrl        { $$ = LSCPSERVER->CreateFxSend($3,$5);            }
457                        |  FX_SEND SP sampler_channel SP midi_ctrl SP fx_send_name  { $$ = LSCPSERVER->CreateFxSend($3,$5,$7); }                        |  FX_SEND SP sampler_channel SP midi_ctrl SP fx_send_name  { $$ = LSCPSERVER->CreateFxSend($3,$5,$7); }
458                          |  EFFECT_INSTANCE SP effect_index                { $$ = LSCPSERVER->CreateEffectInstance($3);       }
459                          |  EFFECT_INSTANCE SP effect_system SP module SP effect_name  { $$ = LSCPSERVER->CreateEffectInstance($3,$5,$7); }
460                        ;                        ;
461    
462  reset_instruction     :  CHANNEL SP sampler_channel  { $$ = LSCPSERVER->ResetChannel($3); }  reset_instruction     :  CHANNEL SP sampler_channel  { $$ = LSCPSERVER->ResetChannel($3); }
# Line 362  find_instruction      :  DB_INSTRUMENTS Line 470  find_instruction      :  DB_INSTRUMENTS
470                        |  DB_INSTRUMENTS SP db_path SP query_val_list                               { $$ = LSCPSERVER->FindDbInstruments($3,$5, true);            }                        |  DB_INSTRUMENTS SP db_path SP query_val_list                               { $$ = LSCPSERVER->FindDbInstruments($3,$5, true);            }
471                        |  DB_INSTRUMENT_DIRECTORIES SP NON_RECURSIVE SP db_path SP query_val_list   { $$ = LSCPSERVER->FindDbInstrumentDirectories($5,$7, false); }                        |  DB_INSTRUMENT_DIRECTORIES SP NON_RECURSIVE SP db_path SP query_val_list   { $$ = LSCPSERVER->FindDbInstrumentDirectories($5,$7, false); }
472                        |  DB_INSTRUMENT_DIRECTORIES SP db_path SP query_val_list                    { $$ = LSCPSERVER->FindDbInstrumentDirectories($3,$5, true);  }                        |  DB_INSTRUMENT_DIRECTORIES SP db_path SP query_val_list                    { $$ = LSCPSERVER->FindDbInstrumentDirectories($3,$5, true);  }
473                          |  LOST SP DB_INSTRUMENT_FILES                                               { $$ = LSCPSERVER->FindLostDbInstrumentFiles();                 }
474                        ;                        ;
475    
476  move_instruction      :  DB_INSTRUMENT_DIRECTORY SP db_path SP db_path    { $$ = LSCPSERVER->MoveDbInstrumentDirectory($3,$5); }  move_instruction      :  DB_INSTRUMENT_DIRECTORY SP db_path SP db_path    { $$ = LSCPSERVER->MoveDbInstrumentDirectory($3,$5); }
# Line 375  copy_instruction      :  DB_INSTRUMENT_D Line 484  copy_instruction      :  DB_INSTRUMENT_D
484  destroy_instruction   :  AUDIO_OUTPUT_DEVICE SP number  { $$ = LSCPSERVER->DestroyAudioOutputDevice($3); }  destroy_instruction   :  AUDIO_OUTPUT_DEVICE SP number  { $$ = LSCPSERVER->DestroyAudioOutputDevice($3); }
485                        |  MIDI_INPUT_DEVICE SP number    { $$ = LSCPSERVER->DestroyMidiInputDevice($3);   }                        |  MIDI_INPUT_DEVICE SP number    { $$ = LSCPSERVER->DestroyMidiInputDevice($3);   }
486                        |  FX_SEND SP sampler_channel SP fx_send_id  { $$ = LSCPSERVER->DestroyFxSend($3,$5); }                        |  FX_SEND SP sampler_channel SP fx_send_id  { $$ = LSCPSERVER->DestroyFxSend($3,$5); }
487                          |  EFFECT_INSTANCE SP number      { $$ = LSCPSERVER->DestroyEffectInstance($3);    }
488                        ;                        ;
489    
490  load_instruction      :  INSTRUMENT SP load_instr_args  { $$ = $3; }  load_instruction      :  INSTRUMENT SP load_instr_args  { $$ = $3; }
491                        |  ENGINE SP load_engine_args     { $$ = $3; }                        |  ENGINE SP load_engine_args     { $$ = $3; }
492                        ;                        ;
493    
494    append_instruction    :  SEND_EFFECT_CHAIN SP EFFECT SP device_index SP effect_chain SP effect_instance  { $$ = LSCPSERVER->AppendSendEffectChainEffect($5,$7,$9); }
495                          ;
496    
497    insert_instruction    :  SEND_EFFECT_CHAIN SP EFFECT SP device_index SP effect_chain SP chain_pos SP effect_instance  { $$ = LSCPSERVER->InsertSendEffectChainEffect($5,$7,$9,$11); }
498                          ;
499    
500  set_chan_instruction  :  AUDIO_OUTPUT_DEVICE SP sampler_channel SP device_index                                              { $$ = LSCPSERVER->SetAudioOutputDevice($5, $3);      }  set_chan_instruction  :  AUDIO_OUTPUT_DEVICE SP sampler_channel SP device_index                                              { $$ = LSCPSERVER->SetAudioOutputDevice($5, $3);      }
501                        |  AUDIO_OUTPUT_CHANNEL SP sampler_channel SP audio_channel_index SP audio_channel_index               { $$ = LSCPSERVER->SetAudioOutputChannel($5, $7, $3); }                        |  AUDIO_OUTPUT_CHANNEL SP sampler_channel SP audio_channel_index SP audio_channel_index               { $$ = LSCPSERVER->SetAudioOutputChannel($5, $7, $3); }
502                        |  AUDIO_OUTPUT_TYPE SP sampler_channel SP audio_output_type_name                                      { $$ = LSCPSERVER->SetAudioOutputType($5, $3);        }                        |  AUDIO_OUTPUT_TYPE SP sampler_channel SP audio_output_type_name                                      { $$ = LSCPSERVER->SetAudioOutputType($5, $3);        }
# Line 397  set_chan_instruction  :  AUDIO_OUTPUT_DE Line 513  set_chan_instruction  :  AUDIO_OUTPUT_DE
513                        |  MIDI_INSTRUMENT_MAP SP sampler_channel SP DEFAULT                                                   { $$ = LSCPSERVER->SetChannelMap($3, -2);             }                        |  MIDI_INSTRUMENT_MAP SP sampler_channel SP DEFAULT                                                   { $$ = LSCPSERVER->SetChannelMap($3, -2);             }
514                        ;                        ;
515    
516  edit_instruction      :  INSTRUMENT SP sampler_channel  { $$ = LSCPSERVER->EditSamplerChannelInstrument($3); }  edit_instruction      :  CHANNEL SP INSTRUMENT SP sampler_channel  { $$ = LSCPSERVER->EditSamplerChannelInstrument($5); }
517                          ;
518    
519    format_instruction    :  INSTRUMENTS_DB  { $$ = LSCPSERVER->FormatInstrumentsDb(); }
520                        ;                        ;
521    
522  modal_arg             :  /* epsilon (empty argument) */  { $$ = true;  }  modal_arg             :  /* epsilon (empty argument) */  { $$ = true;  }
# Line 415  buffer_size_type      :  BYTES       { $ Line 534  buffer_size_type      :  BYTES       { $
534  list_instruction      :  AUDIO_OUTPUT_DEVICES                               { $$ = LSCPSERVER->GetAudioOutputDevices();              }  list_instruction      :  AUDIO_OUTPUT_DEVICES                               { $$ = LSCPSERVER->GetAudioOutputDevices();              }
535                        |  MIDI_INPUT_DEVICES                                 { $$ = LSCPSERVER->GetMidiInputDevices();                }                        |  MIDI_INPUT_DEVICES                                 { $$ = LSCPSERVER->GetMidiInputDevices();                }
536                        |  CHANNELS                                           { $$ = LSCPSERVER->ListChannels();                       }                        |  CHANNELS                                           { $$ = LSCPSERVER->ListChannels();                       }
537                          |  CHANNEL SP MIDI_INPUTS SP sampler_channel          { $$ = LSCPSERVER->ListChannelMidiInputs($5);            }
538                        |  AVAILABLE_ENGINES                                  { $$ = LSCPSERVER->ListAvailableEngines();               }                        |  AVAILABLE_ENGINES                                  { $$ = LSCPSERVER->ListAvailableEngines();               }
539                          |  AVAILABLE_EFFECTS                                  { $$ = LSCPSERVER->ListAvailableEffects();               }
540                          |  EFFECT_INSTANCES                                   { $$ = LSCPSERVER->ListEffectInstances();                }
541                          |  SEND_EFFECT_CHAINS SP number                       { $$ = LSCPSERVER->ListSendEffectChains($3);             }
542                        |  AVAILABLE_MIDI_INPUT_DRIVERS                       { $$ = LSCPSERVER->ListAvailableMidiInputDrivers();      }                        |  AVAILABLE_MIDI_INPUT_DRIVERS                       { $$ = LSCPSERVER->ListAvailableMidiInputDrivers();      }
543                        |  AVAILABLE_AUDIO_OUTPUT_DRIVERS                     { $$ = LSCPSERVER->ListAvailableAudioOutputDrivers();    }                        |  AVAILABLE_AUDIO_OUTPUT_DRIVERS                     { $$ = LSCPSERVER->ListAvailableAudioOutputDrivers();    }
544                        |  MIDI_INSTRUMENTS SP midi_map                       { $$ = LSCPSERVER->ListMidiInstrumentMappings($3);       }                        |  MIDI_INSTRUMENTS SP midi_map                       { $$ = LSCPSERVER->ListMidiInstrumentMappings($3);       }
# Line 426  list_instruction      :  AUDIO_OUTPUT_DE Line 549  list_instruction      :  AUDIO_OUTPUT_DE
549                        |  DB_INSTRUMENT_DIRECTORIES SP db_path               { $$ = LSCPSERVER->GetDbInstrumentDirectories($3);       }                        |  DB_INSTRUMENT_DIRECTORIES SP db_path               { $$ = LSCPSERVER->GetDbInstrumentDirectories($3);       }
550                        |  DB_INSTRUMENTS SP RECURSIVE SP db_path             { $$ = LSCPSERVER->GetDbInstruments($5, true);           }                        |  DB_INSTRUMENTS SP RECURSIVE SP db_path             { $$ = LSCPSERVER->GetDbInstruments($5, true);           }
551                        |  DB_INSTRUMENTS SP db_path                          { $$ = LSCPSERVER->GetDbInstruments($3);                 }                        |  DB_INSTRUMENTS SP db_path                          { $$ = LSCPSERVER->GetDbInstruments($3);                 }
552                          |  FILE SP INSTRUMENTS SP filename                    { $$ = LSCPSERVER->ListFileInstruments($5);              }
553                          ;
554    
555    send_instruction      :  CHANNEL SP MIDI_DATA SP string SP sampler_channel SP number SP number  { $$ = LSCPSERVER->SendChannelMidiData($5, $7, $9, $11); }
556                        ;                        ;
557    
558  load_instr_args       :  filename SP instrument_index SP sampler_channel               { $$ = LSCPSERVER->LoadInstrument($1, $3, $5);       }  load_instr_args       :  filename SP instrument_index SP sampler_channel               { $$ = LSCPSERVER->LoadInstrument($1, $3, $5);       }
# Line 440  instr_load_mode       :  ON_DEMAND Line 567  instr_load_mode       :  ON_DEMAND
567                        |  PERSISTENT      { $$ = MidiInstrumentMapper::PERSISTENT;     }                        |  PERSISTENT      { $$ = MidiInstrumentMapper::PERSISTENT;     }
568                        ;                        ;
569    
570    effect_instance           : number
571                              ;
572    
573  device_index              :  number  device_index              :  number
574                            ;                            ;
575    
# Line 475  volume_value              :  dotnum Line 605  volume_value              :  dotnum
605                            |  number  { $$ = $1; }                            |  number  { $$ = $1; }
606                            ;                            ;
607    
608    control_value             :  real
609                              ;
610    
611  sampler_channel           :  number  sampler_channel           :  number
612                            ;                            ;
613    
# Line 487  fx_send_id                :  number Line 620  fx_send_id                :  number
620  engine_name               :  string  engine_name               :  string
621                            ;                            ;
622    
623  filename                  :  path  { $$ = $1.toPosix(); /*TODO: assuming POSIX*/ }  filename                  :  path  {
624                                     #if WIN32
625                                     $$ = $1.toWindows();
626                                     #else
627                                     // assuming POSIX
628                                     $$ = $1.toPosix();
629                                     #endif
630                                 }
631                            ;                            ;
632    
633  db_path                   :  path  { $$ = $1.toDbPath(); }  db_path                   :  path  { $$ = $1.toDbPath(); }
634                            ;                            ;
635    
636  map_name                  :  stringval  map_name                  :  stringval_escaped
637                              ;
638    
639    entry_name                :  stringval_escaped
640                              ;
641    
642    fx_send_name              :  stringval_escaped
643                              ;
644    
645    effect_name               :  stringval_escaped
646                              ;
647    
648    effect_index              :  number
649                              ;
650    
651    effect_chain              :  number
652                            ;                            ;
653    
654  entry_name                :  stringval  chain_pos                 :  number
655                            ;                            ;
656    
657  fx_send_name              :  stringval  input_control             :  number
658                            ;                            ;
659    
660  param_val_list            :  param_val  param_val_list            :  param_val
661                            |  param_val_list','param_val  { $$ = $1 + "," + $3; }                            |  param_val_list','param_val  { $$ = $1 + "," + $3; }
662                            ;                            ;
663    
664  param_val                 :  string  //TODO: the re-encapsulation into apostrophes for string and strinval here is a hack, since we need a way for __parse_strings() (DeviceParameters.cpp) to distinguish a comma separated list of strings and a string which contains commas. A clean solution would be to move those parser jobs over here to lscp.y
665                            |  stringval  param_val                 :  string            { $$ = "\'" + $1 + "\'"; }
666                              |  stringval         { $$ = "\'" + $1 + "\'"; }
667                            |  number            { std::stringstream ss; ss << "\'" << $1 << "\'"; $$ = ss.str(); }                            |  number            { std::stringstream ss; ss << "\'" << $1 << "\'"; $$ = ss.str(); }
668                            |  dotnum            { std::stringstream ss; ss << "\'" << $1 << "\'"; $$ = ss.str(); }                            |  dotnum            { std::stringstream ss; ss << "\'" << $1 << "\'"; $$ = ss.str(); } //TODO: maybe better using 'real' instead of 'number' and 'dotnum' rules
669                            ;                            ;
670    
671  query_val_list            :  string '=' query_val                    { $$[$1] = $3;          }  query_val_list            :  string '=' query_val                    { $$[$1] = $3;          }
672                            |  query_val_list SP string '=' query_val  { $$ = $1; $$[$3] = $5; }                            |  query_val_list SP string '=' query_val  { $$ = $1; $$[$3] = $5; }
673                            ;                            ;
674    
675  query_val                 :  textval_escaped  query_val                 :  text_escaped
676                            |  stringval_escaped                            |  stringval_escaped
677                            ;                            ;
678    
# Line 525  scan_mode                 :  RECURSIVE Line 681  scan_mode                 :  RECURSIVE
681                            |  FLAT           { $$ = "FLAT"; }                            |  FLAT           { $$ = "FLAT"; }
682                            ;                            ;
683    
684    effect_system             :  string
685                              ;
686    
687    module                    :  filename
688                              ;
689    
690  // GRAMMAR_BNF_END - do NOT delete or modify this line !!!  // GRAMMAR_BNF_END - do NOT delete or modify this line !!!
691    
692    
# Line 534  boolean               :  number  { $$ = Line 696  boolean               :  number  { $$ =
696                        |  string  { $$ = -1; }                        |  string  { $$ = -1; }
697                        ;                        ;
698    
699  dotnum                :      digits '.' digits  { $$ = atof(String($1 + "." + $3).c_str());                         }  dotnum                :      digits '.' digits  { std::stringstream ss($1 + "." + $3); ss.imbue(std::locale::classic()); ss >> $$; }
700                        |  '+' digits '.' digits  { String s = "+"; s += $2; s += "."; s += $4; $$ = atof(s.c_str()); }                        |  '+' digits '.' digits  { std::stringstream ss($2 + "." + $4); ss.imbue(std::locale::classic()); ss >> $$; }
701                        |  '-' digits '.' digits  { $$ = atof(String("-" + $2 + "." + $4).c_str());                   }                        |  '-' digits '.' digits  { std::stringstream ss("-" + $2 + "." + $4); ss.imbue(std::locale::classic()); ss >> $$; }
702                          ;
703    
704    real                  :      digits '.' digits  { std::stringstream ss($1 + "." + $3); ss.imbue(std::locale::classic()); ss >> $$; }
705                          |  '+' digits '.' digits  { std::stringstream ss($2 + "." + $4); ss.imbue(std::locale::classic()); ss >> $$; }
706                          |  '-' digits '.' digits  { std::stringstream ss("-" + $2 + "." + $4); ss.imbue(std::locale::classic()); ss >> $$; }
707                          |      digits             { std::stringstream ss($1); ss.imbue(std::locale::classic()); ss >> $$;                  }
708                          |  '+' digits             { std::stringstream ss($2); ss.imbue(std::locale::classic()); ss >> $$;                  }
709                          |  '-' digits             { std::stringstream ss("-" + $2); ss.imbue(std::locale::classic()); ss >> $$;            }
710                        ;                        ;
711    
712    
# Line 606  path                  :  '\'' path_base Line 776  path                  :  '\'' path_base
776                        |  '\"' path_base '\"'  { $$ = $2; }                        |  '\"' path_base '\"'  { $$ = $2; }
777                        ;                        ;
778    
779  path_base             :  '/'                     { $$ = Path();                           }  path_base             :  path_prefix path_body  { $$ = $1 + $2; }
780                        |  path_base '/'           { $$ = $1;                               }                        ;
781                        |  path_base text_escaped  { Path p; p.appendNode($2); $$ = $1 + p; }  
782    path_prefix           :  '/'                 { $$ = Path();                    }
783                          |  alpha_char ':' '/'  { Path p; p.setDrive($1); $$ = p; }
784                          ;
785    
786    path_body             :  /* epsilon (empty argument) */ { $$ = Path();                           }
787                          |  path_body '/'                  { $$ = $1;                               }
788                          |  path_body text_escaped_base    { Path p; p.appendNode($2); $$ = $1 + p; }
789                        ;                        ;
790    
791  stringval             :  '\'' text '\''  { $$ = $2; }  stringval             :  '\'' text '\''  { $$ = $2; }
792                        |  '\"' text '\"'  { $$ = $2; }                        |  '\"' text '\"'  { $$ = $2; }
793                        ;                        ;
794    
795  stringval_escaped     :  '\'' textval_escaped '\''  { $$ = $2; }  stringval_escaped     :  '\'' text_escaped '\''  { $$ = $2; }
796                        |  '\"' textval_escaped '\"'  { $$ = $2; }                        |  '\"' text_escaped '\"'  { $$ = $2; }
797                        ;                        ;
798    
799  text                  :  SP           { $$ = " ";      }  text                  :  SP           { $$ = " ";      }
# Line 625  text                  :  SP           { Line 802  text                  :  SP           {
802                        |  text string  { $$ = $1 + $2;  }                        |  text string  { $$ = $1 + $2;  }
803                        ;                        ;
804    
805  text_escaped          :  SP                           { $$ = " ";      }  // like text_escaped, but missing the slash ('/') character
806    text_escaped_base     :  SP                                { $$ = " ";      }
807                        |  string_escaped                        |  string_escaped
808                        |  text_escaped SP              { $$ = $1 + " "; }                        |  text_escaped_base SP              { $$ = $1 + " "; }
809                        |  text_escaped string_escaped  { $$ = $1 + $2;  }                        |  text_escaped_base string_escaped  { $$ = $1 + $2;  }
810                        ;                        ;
811    
812  textval_escaped       :  '/'                           { $$ = "/";      }  text_escaped          :  '/'                              { $$ = "/";      }
813                        |  text_escaped                        |  text_escaped_base
814                        |  textval_escaped '/'           { $$ = $1 + "/"; }                        |  text_escaped '/'                 { $$ = $1 + "/"; }
815                        |  textval_escaped text_escaped  { $$ = $1 + $2;  }                        |  text_escaped text_escaped_base   { $$ = $1 + $2;  }
816                        ;                        ;
817    
818  string                :  char          { std::string s; s = $1; $$ = s; }  string                :  char          { std::string s; s = $1; $$ = s; }
# Line 653  char                  :  char_base Line 831  char                  :  char_base
831                        |  '/'   { $$ = '/';  }                        |  '/'   { $$ = '/';  }
832                        ;                        ;
833    
834  // ASCII characters except space, quotation mark, apostrophe, backslash and slash  // characters A..Z and a..z
835  char_base             :  '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'; }  alpha_char            :  'A' { $$ = 'A'; } | 'B' { $$ = 'B'; } | 'C' { $$ = 'C'; } | 'D' { $$ = 'D'; } | 'E' { $$ = 'E'; } | 'F' { $$ = 'F'; } | 'G' { $$ = 'G'; } | 'H' { $$ = 'H'; } | 'I' { $$ = 'I'; } | 'J' { $$ = 'J'; } | 'K' { $$ = 'K'; } | 'L' { $$ = 'L'; } | 'M' { $$ = 'M'; } | 'N' { $$ = 'N'; } | 'O' { $$ = 'O'; } | 'P' { $$ = 'P'; } | 'Q' { $$ = 'Q'; } | 'R' { $$ = 'R'; } | 'S' { $$ = 'S'; } | 'T' { $$ = 'T'; } | 'U' { $$ = 'U'; } | 'V' { $$ = 'V'; } | 'W' { $$ = 'W'; } | 'X' { $$ = 'X'; } | 'Y' { $$ = 'Y'; } | 'Z' { $$ = 'Z'; }
836                        |  'a' { $$ = 'a'; } | 'b' { $$ = 'b'; } | 'c' { $$ = 'c'; } | 'd' { $$ = 'd'; } | 'e' { $$ = 'e'; } | 'f' { $$ = 'f'; } | 'g' { $$ = 'g'; } | 'h' { $$ = 'h'; } | 'i' { $$ = 'i'; } | 'j' { $$ = 'j'; } | 'k' { $$ = 'k'; } | 'l' { $$ = 'l'; } | 'm' { $$ = 'm'; } | 'n' { $$ = 'n'; } | 'o' { $$ = 'o'; } | 'p' { $$ = 'p'; } | 'q' { $$ = 'q'; } | 'r' { $$ = 'r'; } | 's' { $$ = 's'; } | 't' { $$ = 't'; } | 'u' { $$ = 'u'; } | 'v' { $$ = 'v'; } | 'w' { $$ = 'w'; } | 'x' { $$ = 'x'; } | 'y' { $$ = 'y'; } | 'z' { $$ = 'z'; }                        |  'a' { $$ = 'a'; } | 'b' { $$ = 'b'; } | 'c' { $$ = 'c'; } | 'd' { $$ = 'd'; } | 'e' { $$ = 'e'; } | 'f' { $$ = 'f'; } | 'g' { $$ = 'g'; } | 'h' { $$ = 'h'; } | 'i' { $$ = 'i'; } | 'j' { $$ = 'j'; } | 'k' { $$ = 'k'; } | 'l' { $$ = 'l'; } | 'm' { $$ = 'm'; } | 'n' { $$ = 'n'; } | 'o' { $$ = 'o'; } | 'p' { $$ = 'p'; } | 'q' { $$ = 'q'; } | 'r' { $$ = 'r'; } | 's' { $$ = 's'; } | 't' { $$ = 't'; } | 'u' { $$ = 'u'; } | 'v' { $$ = 'v'; } | 'w' { $$ = 'w'; } | 'x' { $$ = 'x'; } | 'y' { $$ = 'y'; } | 'z' { $$ = 'z'; }
837                          ;
838    
839    // ASCII characters except space, quotation mark, apostrophe, backslash and slash
840    char_base             :  alpha_char
841                        |  '0' { $$ = '0'; } | '1' { $$ = '1'; } | '2' { $$ = '2'; } | '3' { $$ = '3'; } | '4' { $$ = '4'; } | '5' { $$ = '5'; } | '6' { $$ = '6'; } | '7' { $$ = '7'; } | '8' { $$ = '8'; } | '9' { $$ = '9'; }                        |  '0' { $$ = '0'; } | '1' { $$ = '1'; } | '2' { $$ = '2'; } | '3' { $$ = '3'; } | '4' { $$ = '4'; } | '5' { $$ = '5'; } | '6' { $$ = '6'; } | '7' { $$ = '7'; } | '8' { $$ = '8'; } | '9' { $$ = '9'; }
842                        |  '!' { $$ = '!'; } | '#' { $$ = '#'; } | '$' { $$ = '$'; } | '%' { $$ = '%'; } | '&' { $$ = '&'; } | '(' { $$ = '('; } | ')' { $$ = ')'; } | '*' { $$ = '*'; } | '+' { $$ = '+'; } | '-' { $$ = '-'; } | '.' { $$ = '.'; } | ',' { $$ = ','; }                        |  '!' { $$ = '!'; } | '#' { $$ = '#'; } | '$' { $$ = '$'; } | '%' { $$ = '%'; } | '&' { $$ = '&'; } | '(' { $$ = '('; } | ')' { $$ = ')'; } | '*' { $$ = '*'; } | '+' { $$ = '+'; } | '-' { $$ = '-'; } | '.' { $$ = '.'; } | ',' { $$ = ','; }
843                        |  ':' { $$ = ':'; } | ';' { $$ = ';'; } | '<' { $$ = '<'; } | '=' { $$ = '='; } | '>' { $$ = '>'; } | '?' { $$ = '?'; } | '@' { $$ = '@'; }                        |  ':' { $$ = ':'; } | ';' { $$ = ';'; } | '<' { $$ = '<'; } | '=' { $$ = '='; } | '>' { $$ = '>'; } | '?' { $$ = '?'; } | '@' { $$ = '@'; }
# Line 715  CLEAR                 :  'C''L''E''A''R' Line 897  CLEAR                 :  'C''L''E''A''R'
897  FIND                  :  'F''I''N''D'  FIND                  :  'F''I''N''D'
898                        ;                        ;
899    
900    FILE_AS_DIR           :  'F''I''L''E''_''A''S''_''D''I''R'
901                          ;
902    
903  MOVE                  :  'M''O''V''E'  MOVE                  :  'M''O''V''E'
904                        ;                        ;
905    
# Line 751  REMOVE                :  'R''E''M''O''V' Line 936  REMOVE                :  'R''E''M''O''V'
936  SET                   :  'S''E''T'  SET                   :  'S''E''T'
937                        ;                        ;
938    
939    SHELL                 :  'S''H''E''L''L'
940                          ;
941    
942    INTERACT              :  'I''N''T''E''R''A''C''T'
943                          ;
944    
945    AUTO_CORRECT          :  'A''U''T''O''_''C''O''R''R''E''C''T'
946                          ;
947    
948    APPEND                :  'A''P''P''E''N''D'
949                          ;
950    
951    INSERT                :  'I''N''S''E''R''T'
952                          ;
953    
954  SUBSCRIBE             :  'S''U''B''S''C''R''I''B''E'  SUBSCRIBE             :  'S''U''B''S''C''R''I''B''E'
955                        ;                        ;
956    
# Line 808  DB_INSTRUMENT_COUNT           :  'D''B'' Line 1008  DB_INSTRUMENT_COUNT           :  'D''B''
1008  DB_INSTRUMENT_INFO            :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''I''N''F''O'  DB_INSTRUMENT_INFO            :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''I''N''F''O'
1009                                ;                                ;
1010    
1011    DB_INSTRUMENT_FILES           :  'D''B''_''I''N''S''T''R''U''M''E''N''T''_''F''I''L''E''S'
1012                                  ;
1013    
1014  DB_INSTRUMENTS_JOB_INFO       :  'D''B''_''I''N''S''T''R''U''M''E''N''T''S''_''J''O''B''_''I''N''F''O'  DB_INSTRUMENTS_JOB_INFO       :  'D''B''_''I''N''S''T''R''U''M''E''N''T''S''_''J''O''B''_''I''N''F''O'
1015                                ;                                ;
1016    
1017  CHANNEL_COUNT        :  'C''H''A''N''N''E''L''_''C''O''U''N''T'  CHANNEL_COUNT        :  'C''H''A''N''N''E''L''_''C''O''U''N''T'
1018                       ;                       ;
1019    
1020    CHANNEL_MIDI         :  'C''H''A''N''N''E''L''_''M''I''D''I'
1021                         ;
1022    
1023    DEVICE_MIDI          :  'D''E''V''I''C''E''_''M''I''D''I'
1024                         ;
1025    
1026  CHANNEL_INFO         :  'C''H''A''N''N''E''L''_''I''N''F''O'  CHANNEL_INFO         :  'C''H''A''N''N''E''L''_''I''N''F''O'
1027                       ;                       ;
1028    
# Line 832  STREAM_COUNT         :  'S''T''R''E''A'' Line 1041  STREAM_COUNT         :  'S''T''R''E''A''
1041  VOICE_COUNT          :  'V''O''I''C''E''_''C''O''U''N''T'  VOICE_COUNT          :  'V''O''I''C''E''_''C''O''U''N''T'
1042                       ;                       ;
1043    
1044    TOTAL_STREAM_COUNT   :  'T''O''T''A''L''_''S''T''R''E''A''M''_''C''O''U''N''T'
1045                         ;
1046    
1047  TOTAL_VOICE_COUNT    :  'T''O''T''A''L''_''V''O''I''C''E''_''C''O''U''N''T'  TOTAL_VOICE_COUNT    :  'T''O''T''A''L''_''V''O''I''C''E''_''C''O''U''N''T'
1048                       ;                       ;
1049    
# Line 841  TOTAL_VOICE_COUNT_MAX:  'T''O''T''A''L'' Line 1053  TOTAL_VOICE_COUNT_MAX:  'T''O''T''A''L''
1053  GLOBAL_INFO          :  'G''L''O''B''A''L''_''I''N''F''O'  GLOBAL_INFO          :  'G''L''O''B''A''L''_''I''N''F''O'
1054                       ;                       ;
1055    
1056    EFFECT_INSTANCE_COUNT   :  'E''F''F''E''C''T''_''I''N''S''T''A''N''C''E''_''C''O''U''N''T'
1057                            ;
1058    
1059    EFFECT_INSTANCE_INFO    :  'E''F''F''E''C''T''_''I''N''S''T''A''N''C''E''_''I''N''F''O'
1060                            ;
1061    
1062    SEND_EFFECT_CHAIN_COUNT :  'S''E''N''D''_''E''F''F''E''C''T''_''C''H''A''I''N''_''C''O''U''N''T'
1063                            ;
1064    
1065    SEND_EFFECT_CHAIN_INFO  :  'S''E''N''D''_''E''F''F''E''C''T''_''C''H''A''I''N''_''I''N''F''O'
1066                            ;
1067    
1068  INSTRUMENT           :  'I''N''S''T''R''U''M''E''N''T'  INSTRUMENT           :  'I''N''S''T''R''U''M''E''N''T'
1069                       ;                       ;
1070    
1071    INSTRUMENTS          :  'I''N''S''T''R''U''M''E''N''T''S'
1072                         ;
1073    
1074  ENGINE               :  'E' 'N' 'G' 'I' 'N' 'E'  ENGINE               :  'E' 'N' 'G' 'I' 'N' 'E'
1075                       ;                       ;
1076    
# Line 880  AUDIO_OUTPUT_CHANNEL  :  'A''U''D''I''O' Line 1107  AUDIO_OUTPUT_CHANNEL  :  'A''U''D''I''O'
1107  AUDIO_OUTPUT_TYPE     :  'A''U''D''I''O''_''O''U''T''P''U''T''_''T''Y''P''E'  AUDIO_OUTPUT_TYPE     :  'A''U''D''I''O''_''O''U''T''P''U''T''_''T''Y''P''E'
1108                        ;                        ;
1109    
1110    AVAILABLE_EFFECTS :  'A''V''A''I''L''A''B''L''E''_''E''F''F''E''C''T''S'
1111                      ;
1112    
1113    EFFECT :  'E''F''F''E''C''T'
1114           ;
1115    
1116    EFFECT_INSTANCE :  'E''F''F''E''C''T''_''I''N''S''T''A''N''C''E'
1117                    ;
1118    
1119    EFFECT_INSTANCES :  'E''F''F''E''C''T''_''I''N''S''T''A''N''C''E''S'
1120                     ;
1121    
1122    EFFECT_INSTANCE_INPUT_CONTROL :  'E''F''F''E''C''T''_''I''N''S''T''A''N''C''E''_''I''N''P''U''T''_''C''O''N''T''R''O''L'
1123                                  ;
1124    
1125    SEND_EFFECT_CHAIN :  'S''E''N''D''_''E''F''F''E''C''T''_''C''H''A''I''N'
1126                      ;
1127    
1128    SEND_EFFECT_CHAINS :  'S''E''N''D''_''E''F''F''E''C''T''_''C''H''A''I''N''S'
1129                       ;
1130    
1131  AVAILABLE_MIDI_INPUT_DRIVERS  :  'A''V''A''I''L''A''B''L''E''_''M''I''D''I''_''I''N''P''U''T''_''D''R''I''V''E''R''S'  AVAILABLE_MIDI_INPUT_DRIVERS  :  'A''V''A''I''L''A''B''L''E''_''M''I''D''I''_''I''N''P''U''T''_''D''R''I''V''E''R''S'
1132                                ;                                ;
1133    
# Line 925  MIDI_INPUT_TYPE       :  'M''I''D''I''_' Line 1173  MIDI_INPUT_TYPE       :  'M''I''D''I''_'
1173  MIDI_INPUT            :  'M''I''D''I''_''I''N''P''U''T'  MIDI_INPUT            :  'M''I''D''I''_''I''N''P''U''T'
1174                        ;                        ;
1175    
1176    MIDI_INPUTS           :  'M''I''D''I''_''I''N''P''U''T''S'
1177                          ;
1178    
1179  MIDI_CONTROLLER       :  'M''I''D''I''_''C''O''N''T''R''O''L''L''E''R'  MIDI_CONTROLLER       :  'M''I''D''I''_''C''O''N''T''R''O''L''L''E''R'
1180                        ;                        ;
1181    
1182    SEND                  :  'S''E''N''D'
1183                          ;
1184    
1185  FX_SEND               :  'F''X''_''S''E''N''D'  FX_SEND               :  'F''X''_''S''E''N''D'
1186                        ;                        ;
1187    
# Line 949  DB_INSTRUMENT              :  'D''B''_'' Line 1203  DB_INSTRUMENT              :  'D''B''_''
1203  DB_INSTRUMENTS_JOB         :  'D''B''_''I''N''S''T''R''U''M''E''N''T''S''_''J''O''B'  DB_INSTRUMENTS_JOB         :  'D''B''_''I''N''S''T''R''U''M''E''N''T''S''_''J''O''B'
1204                             ;                             ;
1205    
1206    INSTRUMENTS_DB             :  'I''N''S''T''R''U''M''E''N''T''S''_''D''B'
1207                               ;
1208    
1209  DESCRIPTION                :  'D''E''S''C''R''I''P''T''I''O''N'  DESCRIPTION                :  'D''E''S''C''R''I''P''T''I''O''N'
1210                             ;                             ;
1211    
# Line 964  RECURSIVE                  :  'R''E''C'' Line 1221  RECURSIVE                  :  'R''E''C''
1221  NON_RECURSIVE              :  'N''O''N''_''R''E''C''U''R''S''I''V''E'  NON_RECURSIVE              :  'N''O''N''_''R''E''C''U''R''S''I''V''E'
1222                             ;                             ;
1223    
1224    LOST                       :  'L''O''S''T'
1225                               ;
1226    
1227    FILE_PATH                  :  'F''I''L''E''_''P''A''T''H'
1228                               ;
1229    
1230  SERVER                :  'S''E''R''V''E''R'  SERVER                :  'S''E''R''V''E''R'
1231                        ;                        ;
1232    
# Line 973  VOLUME                :  'V''O''L''U''M' Line 1236  VOLUME                :  'V''O''L''U''M'
1236  LEVEL                 :  'L''E''V''E''L'  LEVEL                 :  'L''E''V''E''L'
1237                        ;                        ;
1238    
1239    VALUE                 :  'V''A''L''U''E'
1240                          ;
1241    
1242  MUTE                  :  'M''U''T''E'  MUTE                  :  'M''U''T''E'
1243                        ;                        ;
1244    
1245  SOLO                  :  'S''O''L''O'  SOLO                  :  'S''O''L''O'
1246                        ;                        ;
1247    
1248    VOICES                :  'V''O''I''C''E''S'
1249                          ;
1250    
1251    STREAMS               :  'S''T''R''E''A''M''S'
1252                          ;
1253    
1254  BYTES                 :  'B''Y''T''E''S'  BYTES                 :  'B''Y''T''E''S'
1255                        ;                        ;
1256    
1257  PERCENTAGE            :  'P''E''R''C''E''N''T''A''G''E'  PERCENTAGE            :  'P''E''R''C''E''N''T''A''G''E'
1258                        ;                        ;
1259    
1260    FILE                  :  'F''I''L''E'
1261                          ;
1262    
1263  EDIT                  :  'E''D''I''T'  EDIT                  :  'E''D''I''T'
1264                        ;                        ;
1265    
1266    FORMAT                :  'F''O''R''M''A''T'
1267                          ;
1268    
1269    MIDI_DATA             :  'M''I''D''I''_''D''A''T''A'
1270                          ;
1271    
1272  RESET                 :  'R''E''S''E''T'  RESET                 :  'R''E''S''E''T'
1273                        ;                        ;
1274    
# Line 1005  QUIT                  :  'Q''U''I''T' Line 1286  QUIT                  :  'Q''U''I''T'
1286    
1287  %%  %%
1288    
1289    // TODO: actually would be fine to have the following bunch of source code in a separate file, however those functions are a) accessing private Bison tables like yytable and b) including the functions from another file here would make the line numbers incorrect on compile errors in auto generated lscpparser.cpp
1290    
1291  /**  /**
1292   * Will be called when an error occured (usually syntax error).   * Additional informations of a grammar symbol.
1293     */
1294    struct BisonSymbolInfo {
1295        bool isTerminalSymbol; ///< Whether the symbol is a terminal or non-termianl symbol. NOTE: Read comment regarding this in _isRuleTerminalSymbol() !!
1296        String nextExpectedChars; ///< According to current parser position: sequence of characters expected next for satisfying this grammar symbol.
1297    };
1298    
1299    #if HAVE_BISON_MAJ >= 3 // Bison 3.x or younger ...
1300    
1301    /**
1302     * Must ONLY be called just before a so called "reduce" parser action:
1303     * Returns true if the grammar rule, which is just about to be "reduced", is a
1304     * terminal symbol (in *our* terms).
1305     *
1306     * Please note that the term "terminal symbol" is a bit confusingly used in
1307     * this source code here around. In Bison's terms, "terminal symbols" are (more
1308     * or less) just the numbers returned by the YYLEX function. Since we decided
1309     * though to use a convenient solution without a separate lexer, and all its
1310     * caveats, all numbers by the yylex() function here are just the ASCII
1311     * numbers of the individual characters received. Based on that however, one
1312     * single character is not what one would intuitively expect of being a
1313     * "terminal symbol", because it is simply too primitive.
1314     *
1315     * So in this LSCP parser source code a "terminal symbol" rather means a
1316     * keyword like "CREATE" or "GET". In the grammal definition above, those are
1317     * however defined as grammar rules (non-terminals in Bison's terms). So this
1318     * function decides like this: if the given grammar rule just contains
1319     * individual characters on the right side of its grammar rule, then it is a
1320     * "terminal symbol" in *our* terms.
1321     *
1322     * @param rule - Bison grammar rule number
1323     * @param stack - reflecting current Bison parser state
1324     */
1325    inline static bool _isRuleTerminalSymbol(int rule, const std::vector<YYTYPE_INT16>& stack) {
1326        int nrhs = yyr2[rule];
1327        for (int i = 0; i < nrhs; ++i)
1328            if (yystos[*(stack.end() - nrhs + i)] >= YYNTOKENS) return false;
1329        return true;
1330    }
1331    
1332    /**
1333     * Must ONLY be called just before a so called "reduce" parser action: Returns
1334     * additional informations to the given grammar rule that is about to be
1335     * "reduced".
1336     *
1337     * @param rule - Bison grammar rule number
1338     * @param stack - reflecting current Bison parser state
1339     * @param nextExpectedChars - must already be filled with the characters
1340     *                            expected to be coming next
1341     */
1342    inline static BisonSymbolInfo _symbolInfoForRule(int rule, const std::vector<YYTYPE_INT16>& stack, const String& nextExpectedChars) {
1343        BisonSymbolInfo info;
1344        info.isTerminalSymbol = _isRuleTerminalSymbol(rule, stack);
1345        if (info.isTerminalSymbol) info.nextExpectedChars  = nextExpectedChars;
1346        return info;
1347    }
1348    
1349    #else // Bison 2.x or older ...
1350    
1351    //TODO: The Bison 2.x code below can probably soon just be deleted. Most Bisonx 2.x versions should be able to compile successfully with the Bison 3.x code above as well (just requires the existence of table yystos[] in the auto generated lscpparser.cpp).
1352    
1353    /**
1354     * Returns true if the given grammar @a rule is a terminal symbol (in *our*
1355     * terms).
1356     *
1357     * Please note that the term "terminal symbol" is a bit confusingly used in
1358     * this source code here around. In Bison's terms, "terminal symbols" are (more
1359     * or less) just the numbers returned by the YYLEX function. Since we decided
1360     * though to use a convenient solution without a separate lexer, and all its
1361     * caveats, all numbers by the yylex() function here are just the ASCII
1362     * numbers of the individual characters received. Based on that however, one
1363     * single character is not what one would intuitively expect of being a
1364     * "terminal symbol", because it is simply too primitive.
1365     *
1366     * So in this LSCP parser source code a "terminal symbol" rather means a
1367     * keyword like "CREATE" or "GET". In the grammal definition above, those are
1368     * however defined as grammar rules (non-terminals in Bison's terms). So this
1369     * function decides like this: if the given grammar rule just contains
1370     * individual characters on the right side of its grammar rule, then it is a
1371     * "terminal symbol" in *our* terms.
1372     *
1373     * @param rule - Bison grammar rule number
1374     */
1375    inline static bool _isRuleTerminalSymbol(int rule) {
1376        for (int i = yyprhs[rule]; yyrhs[i] != -1; ++i)
1377            if (yyrhs[i] >= YYNTOKENS) return false;
1378        return true;
1379    }
1380    
1381    /**
1382     * Returns additional informations to the given grammar @a rule.
1383     *
1384     * @param rule - grammar rule index to retrieve informations about
1385     * @param nextExpectedChars - must already be filled with the characters
1386     *                            expected to be coming next
1387     */
1388    inline static BisonSymbolInfo _symbolInfoForRule(int rule, const String& nextExpectedChars) {
1389        BisonSymbolInfo info;
1390        info.isTerminalSymbol = _isRuleTerminalSymbol(rule);
1391        if (info.isTerminalSymbol) info.nextExpectedChars  = nextExpectedChars;
1392        return info;
1393    }
1394    
1395    #endif // HAVE_BISON_MAJ >= 3
1396    
1397    /**
1398     * Returns the human readable name of the given @a token.
1399     */
1400    inline static String _tokenName(int token) {
1401        String s = yytname[token];
1402        // remove leading and trailing apostrophes that Bison usually adds to
1403        // ASCII characters used directly in grammar rules
1404        if (s.empty()) return s;
1405        if (s[0] == '\'') s.erase(0, 1);
1406        if (s.empty()) return s;
1407        if (s[s.size() - 1] == '\'') s.erase(s.size() - 1);
1408        return s;
1409    }
1410    
1411    /**
1412     * Assumes the given @a token is exactly one character and returns that
1413     * character. This must be changed in future, i.e. in case Unicode characters
1414     * will be introduced in the LSCP grammar one day.
1415     */
1416    inline static char _tokenChar(int token) {
1417        String s = _tokenName(token);
1418        if (s == "\\n") return '\n';
1419        if (s == "\\r") return '\r';
1420        return _tokenName(token)[0];
1421    }
1422    
1423    /**
1424     * Implements Bison's so called "reduce" action, according to Bison's LALR(1)
1425     * parser algorithm.
1426     */
1427    inline static int _yyReduce(std::vector<YYTYPE_INT16>& stack, const int& rule) {
1428        if (stack.empty()) throw 1; // severe error
1429        const int len = yyr2[rule];
1430        stack.resize(stack.size() - len);
1431        YYTYPE_INT16 newState = yypgoto[yyr1[rule] - YYNTOKENS] + stack.back();
1432        if (0 <= newState && newState <= YYLAST && yycheck[newState] == stack.back())
1433            newState = yytable[newState];
1434        else
1435            newState = yydefgoto[yyr1[rule] - YYNTOKENS];
1436        stack.push_back(newState);
1437        return newState;
1438    }
1439    
1440    /**
1441     * Implements Bison's so called "default reduce" action, according to Bison's
1442     * LALR(1) parser algorithm.
1443     */
1444    inline static int _yyDefaultReduce(std::vector<YYTYPE_INT16>& stack) {
1445        if (stack.empty()) throw 2; // severe error
1446        int rule = yydefact[stack.back()];
1447        if (rule <= 0 || rule >= YYNRULES) throw 3; // no rule, something is wrong
1448        return _yyReduce(stack, rule);
1449    }
1450    
1451    static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch);
1452    
1453    #define DEBUG_BISON_SYNTAX_ERROR_WALKER 0
1454    
1455    /**
1456     * Tries to find the next expected grammar symbols according to the given
1457     * precise parse position & state represented by @a stack, according to Bison's
1458     * LALR(1) parser algorithm.
1459     *
1460     * This function is given a Bison parser symbol stack, reflecting the parser's
1461     * entire state at a certain point, i.e. when a syntax error occured. This
1462     * function will then walk ahead the potential parse tree starting from the
1463     * current head of the given symbol stack. This function will call itself
1464     * recursively to scan the individual parse tree branches. As soon as it hits
1465     * on the next non-terminal grammar symbol in one parse tree branch, it adds the
1466     * found non-terminal symbol to @a expectedSymbols and aborts scanning the
1467     * respective tree branch further. If any local parser state is reached a second
1468     * time, the respective parse tree is aborted to avoid any endless recursion.
1469     *
1470     * @param stack - current Bison (yacc) symbol stack to be examined
1471     * @param expectedSymbols - will be filled with next expected grammar symbols
1472     * @param nextExpectedChars - just for internal purpose, due to the recursive
1473     *                            implementation of this function, do supply an
1474     *                            empty character for this argument
1475     * @param depth - just for internal debugging purposes
1476     */
1477    static void walkAndFillExpectedSymbols(
1478        std::vector<YYTYPE_INT16>& stack,
1479        std::map<String,BisonSymbolInfo>& expectedSymbols,
1480        String& nextExpectedChars, int depth = 0)
1481    {
1482    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1483        printf("\n");
1484        for (int i = 0; i < depth; ++i) printf("\t");
1485        printf("Symbol stack:");
1486        for (int i = 0; i < stack.size(); ++i) {
1487            printf(" %d", stack[i]);
1488        }
1489        printf("\n");
1490    #endif
1491        startLabel:
1492    
1493        if (stack.empty()) {
1494    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1495            for (int i = 0; i < depth; ++i) printf("\t");
1496            printf("(EMPTY STACK)\n");
1497    #endif
1498            return;
1499        }
1500    
1501        int state = stack[stack.size() - 1];
1502        int n = yypact[state];
1503        if (n == YYPACT_NINF) { // default reduction required ...
1504            // get default reduction rule for this state
1505            n = yydefact[state];
1506            if (n <= 0 || n >= YYNRULES) {
1507    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1508                for (int i = 0; i < depth; ++i) printf("\t");
1509                printf("(EMPTY RULE)\n");
1510    #endif
1511                return; // no rule, something is wrong
1512            }
1513    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1514            for (int i = 0; i < depth; ++i) printf("\t");
1515            printf("(default reduction)\n");
1516    #endif
1517            #if HAVE_BISON_MAJ >= 3
1518            if (!nextExpectedChars.empty() || !_isRuleTerminalSymbol(n, stack)) {
1519            #else
1520            if (!nextExpectedChars.empty() || !_isRuleTerminalSymbol(n)) {
1521            #endif
1522                // Return the new resolved expected symbol (left-hand symbol of grammar
1523                // rule), then we're done in this state. (If the same symbol can be
1524                // matched on different ways, then it is non-terminal symbol.)
1525                bool ambigious =
1526                    expectedSymbols.count(yytname[yyr1[n]]) &&
1527                    expectedSymbols[yytname[yyr1[n]]].nextExpectedChars != nextExpectedChars;
1528                #if HAVE_BISON_MAJ >= 3
1529                expectedSymbols[yytname[yyr1[n]]] = _symbolInfoForRule(n, stack, nextExpectedChars);
1530                #else
1531                expectedSymbols[yytname[yyr1[n]]] = _symbolInfoForRule(n, nextExpectedChars);
1532                #endif
1533                if (ambigious)
1534                    expectedSymbols[yytname[yyr1[n]]].isTerminalSymbol = false;
1535    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1536                for (int i = 0; i < depth; ++i) printf("\t");
1537                printf("(empty expectedChars. sym = %s)\n", yytname[yyr1[n]]);
1538    #endif
1539                return;
1540            }
1541            _yyReduce(stack, n);
1542            goto startLabel;
1543        }
1544        if (!(YYPACT_NINF < n && n <= YYLAST)) {
1545    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1546            for (int i = 0; i < depth; ++i) printf("\t");
1547            printf("(invalid action B)\n");
1548    #endif
1549            return;
1550        }
1551    
1552        // Check for duplicate states, if duplicates exist return
1553        // (this check is necessary since the introduction of the yyValid() call
1554        // below, which does not care about duplicates).
1555        for (int i = 0; i < stack.size(); ++i)
1556            for (int k = i + 1; k < stack.size(); ++k)
1557                if (stack[i] == stack[k])
1558                    return;
1559    
1560    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1561        for (int i = 0; i < depth; ++i) printf("\t");
1562        printf("Expected tokens:");
1563    #endif
1564        int begin = n < 0 ? -n : 0;
1565        //int checklim = YYLAST - n + 1;
1566        int end = YYNTOKENS;//checklim < YYNTOKENS ? checklim : YYNTOKENS;
1567        int rule, action, stackSize, nextExpectedCharsLen;
1568        for (int token = begin; token < end; ++token) {
1569            if (token <= YYTERROR) continue;
1570            if (yytname[token] == String("$undefined")) continue;
1571            if (yytname[token] == String("EXT_ASCII_CHAR")) continue;
1572            //if (yycheck[n + token] != token) goto default_reduction;
1573            if (yycheck[n + token] != token) { // default reduction suggested ...
1574                // If we are here, it means the current token in the loop would not
1575                // cause a "shift", however we don't already know whether this token
1576                // is valid or not. Because there might be several reductions
1577                // involved until one can determine whether the token causes an
1578                // error or is valid. So we use this heavy check instead:
1579                std::vector<YYTYPE_INT16> stackCopy = stack; // copy required, since reduction will take place
1580                if (!yyValid(stackCopy, _tokenChar(token))) continue; // invalid token
1581    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1582                printf(" ETdr(%s)", yytname[token]);
1583    #endif
1584                // the token is valid, "stackCopy" has been reduced accordingly
1585                // and now do recurse ...
1586                nextExpectedChars += _tokenName(token);
1587                nextExpectedCharsLen = nextExpectedChars.size();
1588                walkAndFillExpectedSymbols( //FIXME: could cause stack overflow (should be a loop instead), is probably fine with our current grammar though
1589                    stackCopy, expectedSymbols, nextExpectedChars, depth + 1
1590                );
1591                nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'
1592                continue;
1593            }
1594    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1595            printf(" ET(%s)", yytname[token]);
1596    #endif
1597    
1598            action = yytable[n + token];
1599            if (action == 0 || action == YYTABLE_NINF) {
1600    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1601                printf(" (invalid action A) "); fflush(stdout);
1602    #endif
1603                continue; // error, ignore
1604            }
1605            if (action < 0) { // reduction with rule -action required ...
1606    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1607                printf(" (reduction) "); fflush(stdout);
1608    #endif
1609                rule = -action;
1610                goto reduce;
1611            }
1612            if (action == YYFINAL) {
1613    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1614                printf(" (ACCEPT) "); fflush(stdout);
1615    #endif
1616                continue; // "accept" state, we don't care about it here
1617            }
1618    
1619            // "shift" required ...
1620    
1621            if (std::find(stack.begin(), stack.end(), action) != stack.end()) {
1622    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1623                printf(" (duplicate state %d) ", action); fflush(stdout);
1624    #endif
1625                continue; // duplicate state, ignore it to avoid endless recursions
1626            }
1627    
1628            // "shift" / push the new state on the symbol stack and call this
1629            // function recursively, and restore the stack after the recurse return
1630            stackSize = stack.size();
1631            nextExpectedCharsLen = nextExpectedChars.size();
1632            stack.push_back(action);
1633            nextExpectedChars += _tokenName(token);
1634            walkAndFillExpectedSymbols( //FIXME: could cause stack overflow (should be a loop instead), is probably fine with our current grammar though
1635                stack, expectedSymbols, nextExpectedChars, depth + 1
1636            );
1637            stack.resize(stackSize); // restore stack
1638            nextExpectedChars.resize(nextExpectedCharsLen); // restore 'nextExpectedChars'
1639            continue;
1640    
1641        //default_reduction: // resolve default reduction for this state
1642        //    printf(" (default red.) "); fflush(stdout);
1643        //    rule = yydefact[state];
1644    
1645        reduce: // "reduce" required
1646    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1647            printf(" (reduce by %d) ", rule); fflush(stdout);
1648    #endif
1649            if (rule == 0 || rule >= YYNRULES) {
1650    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1651                printf(" (invalid rule) "); fflush(stdout);
1652    #endif
1653                continue; // invalid rule, something is wrong
1654            }
1655            // Store the left-hand symbol of the grammar rule. (If the same symbol
1656            // can be matched on different ways, then it is non-terminal symbol.)
1657            bool ambigious =
1658                expectedSymbols.count(yytname[yyr1[rule]]) &&
1659                expectedSymbols[yytname[yyr1[rule]]].nextExpectedChars != nextExpectedChars;
1660            #if HAVE_BISON_MAJ >= 3
1661            expectedSymbols[yytname[yyr1[rule]]] = _symbolInfoForRule(rule, stack, nextExpectedChars);
1662            #else
1663            expectedSymbols[yytname[yyr1[rule]]] = _symbolInfoForRule(rule, nextExpectedChars);
1664            #endif
1665            if (ambigious)
1666                expectedSymbols[yytname[yyr1[n]]].isTerminalSymbol = false;
1667    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1668            printf(" (SYM %s) ", yytname[yyr1[rule]]); fflush(stdout);
1669    #endif
1670        }
1671    #if DEBUG_BISON_SYNTAX_ERROR_WALKER
1672        printf("\n");
1673    #endif
1674    }
1675    
1676    #define DEBUG_PUSH_PARSE 0
1677    
1678    /**
1679     * Implements parsing exactly one character (given by @a c), continueing at the
1680     * parser position reflected by @a stack. The @a stack will hold the new parser
1681     * state after this call.
1682     *
1683     * This function is implemented according to Bison's LALR(1) parser algorithm.
1684     */
1685    static bool yyPushParse(std::vector<YYTYPE_INT16>& stack, char ch) {
1686        startLabel:
1687    
1688    #if DEBUG_PUSH_PARSE
1689        //printf("\n");
1690        //for (int i = 0; i < depth; ++i) printf("\t");
1691        printf("Symbol stack:");
1692        for (int i = 0; i < stack.size(); ++i) {
1693            printf(" %d", stack[i]);
1694        }
1695        printf(" char='%c'(%d)\n", ch, (int)ch);
1696    #endif
1697    
1698        if (stack.empty()) return false;
1699    
1700        int state = stack.back();
1701        int n = yypact[state];
1702        if (n == YYPACT_NINF) { // default reduction required ...
1703    #if DEBUG_PUSH_PARSE
1704            printf("(def reduce 1)\n");
1705    #endif
1706            state = _yyDefaultReduce(stack);
1707            goto startLabel;
1708        }
1709        if (!(YYPACT_NINF < n && n <= YYLAST)) return false;
1710    
1711        YYTYPE_INT16 token = (ch == YYEOF) ? YYEOF : yytranslate[ch];
1712        n += token;
1713        if (n < 0 || YYLAST < n || yycheck[n] != token) {
1714    #if DEBUG_PUSH_PARSE
1715            printf("(def reduce 2) n=%d token=%d\n", n, token);
1716    #endif
1717            state = _yyDefaultReduce(stack);
1718            goto startLabel;
1719        }
1720        int action = yytable[n]; // yytable[yypact[state] + token]
1721        if (action == 0 || action == YYTABLE_NINF) throw 4;
1722        if (action < 0) {
1723    #if DEBUG_PUSH_PARSE
1724            printf("(reduce)\n");
1725    #endif
1726            int rule = -action;
1727            state = _yyReduce(stack, rule);
1728            goto startLabel;
1729        }
1730        if (action == YYFINAL) return true; // final state reached
1731    
1732    #if DEBUG_PUSH_PARSE
1733        printf("(push)\n");
1734    #endif
1735        // push new state
1736        state = action;
1737        stack.push_back(state);
1738        return true;
1739    }
1740    
1741    /**
1742     * Returns true if parsing ahead with given character @a ch is syntactically
1743     * valid according to the LSCP grammar, it returns false if it would create a
1744     * parse error.
1745     *
1746     * The @a stack will reflect the new parser state after this call.
1747     *
1748     * This is just a wrapper ontop of yyPushParse() which converts parser
1749     * exceptions thrown by yyPushParse() into negative return value.
1750   */   */
1751  void yyerror(const char* s) {  static bool yyValid(std::vector<YYTYPE_INT16>& stack, char ch) {
1752        try {
1753            return yyPushParse(stack, ch);
1754        } catch (int i) {
1755    #if DEBUG_PUSH_PARSE
1756            printf("exception %d\n", i);
1757    #endif
1758            return false;
1759        } catch (...) {
1760            return false;
1761        }
1762    }
1763    
1764    /**
1765     * Returns the amount of correct characters of given @a line from the left,
1766     * according to the LSCP grammar.
1767     *
1768     * @param stack - a Bison symbol stack to work with
1769     * @param line  - the input line to check
1770     * @param bAutoCorrect - if true: try to correct obvious, trivial syntax errors
1771     */
1772    static int yyValidCharacters(std::vector<YYTYPE_INT16>& stack, String& line, bool bAutoCorrect) {
1773        int i;
1774        for (i = 0; i < line.size(); ++i) {
1775            // since we might check the same parser state twice against the current
1776            // char here below, and since the symbol stack might be altered
1777            // (i.e. shifted or reduced) on syntax errors, we have to backup the
1778            // current symbol stack and restore it on syntax errors below
1779            std::vector<YYTYPE_INT16> stackCopy = stack;
1780            if (yyValid(stackCopy, line[i])) {
1781                stack = stackCopy;
1782                continue;
1783            }
1784            if (bAutoCorrect) {
1785                // try trivial corrections, i.e. upper case character instead of
1786                // lower case, subline instead of space and vice versa
1787                char c;
1788                if      (line[i] == ' ') c = '_';
1789                else if (line[i] == '_') c = ' ';
1790                else if (isLowerCaseAlphaChar(line[i]))
1791                    c = alphaCharToUpperCase(line[i]);
1792                else return i;
1793                if (yyValid(stack, c)) {
1794                    line[i] = c;
1795                    continue;
1796                }
1797            }
1798            return i;
1799        }
1800        return i;
1801    }
1802    
1803    /**
1804     * Should only be called on syntax errors: returns a set of non-terminal
1805     * symbols expected to appear now/next, just at the point where the syntax
1806     * error appeared.
1807     *
1808     * @returns names of the non-terminal symbols expected at this parse position
1809     */
1810    static std::set<String> yyExpectedSymbols() {
1811        std::map<String,BisonSymbolInfo> expectedSymbols;
1812      yyparse_param_t* param = GetCurrentYaccSession();      yyparse_param_t* param = GetCurrentYaccSession();
1813      String msg = s      YYTYPE_INT16* ss = (*param->ppStackBottom);
1814          + (" (line:"   + ToString(param->iLine+1))      YYTYPE_INT16* sp = (*param->ppStackTop);
1815          + ( ",column:" + ToString(param->iColumn))      int iStackSize   = sp - ss + 1;
1816          + ")";      // copy and wrap parser's symbol stack into a convenient STL container
1817      dmsg(2,("LSCPParser: %s\n", msg.c_str()));      std::vector<YYTYPE_INT16> stack;
1818      sLastError = msg;      for (int i = 0; i < iStackSize; ++i) {
1819            stack.push_back(ss[i]);
1820        }
1821        String notUsedHere;
1822        // do the actual parser work
1823        walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere);
1824    
1825        // convert expectedSymbols to the result set
1826        std::set<String> result;
1827        for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1828             it != expectedSymbols.end(); ++it) result.insert(it->first);
1829        return result;
1830    }
1831    
1832    #define DEBUG_YY_AUTO_COMPLETE 0
1833    
1834    /**
1835     * A set of parser symbol stacks. This type is used in yyAutoComplete() to keep
1836     * track of all previous parser states, for detecting a parser symbol stack that
1837     * has already been before. Because if yyAutoComplete() reaches the exactly same
1838     * parser symbol stack again, it means there is an endless recursion in that
1839     * part of the grammar tree branch and shall not be evaluated any further,
1840     * because it would end up in an endless loop otherwise.
1841     *
1842     * This solution consumes a lot of memory, but unfortunately there is no other
1843     * easy way to solve it. With our grammar and today's memory heap size & memory
1844     * stack size it should be fine though.
1845     */
1846    typedef std::set< std::vector<YYTYPE_INT16> > YYStackHistory;
1847    
1848    /**
1849     * Generates and returns an auto completion string for the current parser
1850     * state given by @a stack. That means, this function will return the longest
1851     * sequence of characters that is uniqueley expected to be sent next by the LSCP
1852     * client. Or in other words, if the LSCP client would send any other
1853     * character(s) than returned here, it would result in a syntax error.
1854     *
1855     * This function takes a Bison symbol @a stack as argument, reflecting the
1856     * current Bison parser state, and evaluates the individual grammar tree
1857     * branches starting from that particular position. It walks along the grammar
1858     * tree as long as there is only one possible tree branch and assembles a string
1859     * of input characters that would lead to that walk through the grammar tree. As
1860     * soon as a position in the grammar tree is reached where there are multiple
1861     * possible tree branches, this algorithm will stop, since the user could have
1862     * multiple possible valid characters he could type at that point, thus auto
1863     * completion would no longer be unique at that point.
1864     *
1865     * Regarding @a history argument: read the description on YYStackHistory for the
1866     * purpose behind this argument.
1867     *
1868     * @param stack - current Bison (yacc) symbol stack to create auto completion for
1869     * @param history - only for internal purpose, keeps a history of all previous
1870     *                  parser symbol stacks (just for avoiding endless recursion in
1871     *                  this auto completion algorithm)
1872     * @param depth - just for internal debugging purposes
1873     * @returns auto completion for current, given parser state
1874     */
1875    static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack, YYStackHistory& history, int depth = 0) {
1876        std::map<String,BisonSymbolInfo> expectedSymbols;
1877        String notUsedHere;
1878        walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere);
1879        if (expectedSymbols.size() == 1) {
1880            String name          = expectedSymbols.begin()->first;
1881            BisonSymbolInfo info = expectedSymbols.begin()->second;
1882    #if DEBUG_YY_AUTO_COMPLETE
1883            for (int q = 0; q < depth; ++q) printf("  ");
1884            printf("(%d) Suggested Sub Completion (sz=%d): type=%s %s -> '%s'\n", depth, expectedSymbols.size(), (info.isTerminalSymbol) ? "T" : "NT", name.c_str(), info.nextExpectedChars.c_str());
1885    #endif
1886            if (info.nextExpectedChars.empty() || !info.isTerminalSymbol) return "";
1887            // parse forward with the suggested auto completion
1888            std::vector<YYTYPE_INT16> stackCopy = stack;
1889            yyValidCharacters(stackCopy, info.nextExpectedChars, false);
1890            // detect endless recursion
1891            if (history.count(stackCopy)) return "";
1892            history.insert(stackCopy);
1893            // recurse and return the expanded auto completion with maximum length
1894            return info.nextExpectedChars + yyAutoComplete(stackCopy, history, depth + 1);
1895        } else if (expectedSymbols.size() == 0) {
1896    #if DEBUG_YY_AUTO_COMPLETE
1897            for (int q = 0; q < depth; ++q) printf("  ");
1898            printf("(%d) No sub suggestion.\n", depth);
1899    #endif
1900            return "";
1901        } else if (expectedSymbols.size() > 1) {
1902    #if DEBUG_YY_AUTO_COMPLETE
1903            for (int q = 0; q < depth; ++q) printf("  ");
1904            printf("(%d) Multiple sub possibilities (before expansion):", depth);
1905            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1906                 it != expectedSymbols.end(); ++it)
1907            {
1908                printf(" %s (..%s)", it->first.c_str(), it->second.nextExpectedChars.c_str());
1909            }
1910            printf("\n");
1911    #endif
1912            // check if any of the possibilites is a non-terminal symbol, if so, we
1913            // have no way for auto completion at this point
1914            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1915                 it != expectedSymbols.end(); ++it)
1916            {
1917                if (!it->second.isTerminalSymbol) {
1918    #if DEBUG_YY_AUTO_COMPLETE
1919                    for (int q = 0; q < depth; ++q) printf("  ");
1920                    printf("(%d) Non-terminal exists. Stop.", depth);
1921    #endif
1922                    return "";
1923                }
1924            }
1925    #if 0 // commented out for now, since practically irrelevant and VERY slow ...
1926            // all possibilities are terminal symbols, so expand all possiblities to
1927            // maximum length with a recursive call for each possibility
1928            for (std::map<String,BisonSymbolInfo>::iterator it = expectedSymbols.begin();
1929                 it != expectedSymbols.end(); ++it)
1930            {
1931                if (it->second.nextExpectedChars.empty() || !it->second.isTerminalSymbol) continue;
1932                // parse forward with this particular suggested auto completion
1933                std::vector<YYTYPE_INT16> stackCopy = stack;
1934                yyValidCharacters(stackCopy, it->second.nextExpectedChars, false);
1935                // detect endless recursion
1936                if (history.count(stackCopy)) continue;
1937                history.insert(stackCopy);
1938                // recurse and return the total possible auto completion for this
1939                // grammar tree branch
1940                it->second.nextExpectedChars += yyAutoComplete(stackCopy, history, depth + 1);
1941            }
1942    #endif
1943            // try to find the longest common string all possibilities start with
1944            // (from the left)
1945            String sCommon;
1946            for (int i = 0; true; ++i) {
1947                char c;
1948                for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1949                     it != expectedSymbols.end(); ++it)
1950                {
1951                    if (i >= it->second.nextExpectedChars.size())
1952                        goto commonSearchEndLabel;
1953                    if (it == expectedSymbols.begin())
1954                        c = it->second.nextExpectedChars[i];
1955                    if (c != it->second.nextExpectedChars[i])
1956                        goto commonSearchEndLabel;
1957                    if (it == --expectedSymbols.end())
1958                        sCommon += c;
1959                }
1960            }
1961            commonSearchEndLabel:
1962    #if DEBUG_YY_AUTO_COMPLETE
1963            for (int q = 0; q < depth; ++q) printf("  ");
1964            printf("(%d) Multiple sub possibilities (after expansion):", depth);
1965            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
1966                 it != expectedSymbols.end(); ++it)
1967            {
1968                printf(" %s (..%s)", it->first.c_str(), it->second.nextExpectedChars.c_str());
1969            }
1970            printf("\n");
1971            for (int q = 0; q < depth; ++q) printf("  ");
1972            printf("(%d) Common sub possibility: '%s'\n", depth, sCommon.c_str());
1973    #endif
1974            return sCommon;
1975        }
1976        return ""; // just pro forma, should never happen though
1977    }
1978    
1979    /**
1980     * Just a convenience wrapper on top of the actual yyAutoComplete()
1981     * implementation. See description above for details.
1982     */
1983    static String yyAutoComplete(std::vector<YYTYPE_INT16>& stack) {
1984        YYStackHistory history;
1985        return yyAutoComplete(stack, history);
1986    }
1987    
1988    namespace LinuxSampler {
1989    
1990    #define DEBUG_SHELL_INTERACTION 0
1991    
1992    /**
1993     * If LSCP shell mode is enabled for the respective LSCP client connection, then
1994     * this function is called on every new byte received from that client. It will
1995     * check the current total input line and reply to the LSCP shell with a
1996     * specially crafted string, which allows the shell to provide colored syntax
1997     * highlighting and potential auto completion in the shell.
1998     *
1999     * It also performs auto correction of obvious & trivial syntax mistakes if
2000     * requested.
2001     *
2002     * The return value of this function will be sent to the client. It contains one
2003     * line specially formatted for the LSCP shell application, which can easily be
2004     * processed by the client/shell for extracting its necessary informations like
2005     * which part of the current command line is syntactically correct, which part
2006     * is incorrect, what could be auto completed right now, etc. So all the heavy
2007     * grammar evaluation tasks are peformed by the LSCP server for the LSCP shell
2008     * application (which is desgined as a thin client), so the LSCP shell
2009     * application will only have to show the results of the LSCP server's
2010     * evaluation to the user on the screen.
2011     *
2012     * @param line - the current command line to be evaluated by LSCP parser
2013     * @param param = reentrant parser session parameters
2014     * @param possibilities - whether all possibilities shall be shown
2015     * @returns LSCP shell response line to be returned to the client
2016     */
2017    String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param, bool possibilities) {
2018        // first, determine how many characters (starting from the left) of the
2019        // given input line are already syntactically correct
2020        std::vector<YYTYPE_INT16> stack;
2021        stack.push_back(0); // every Bison symbol stack starts with state zero
2022        String l = line + '\n'; // '\n' to pretend ENTER as if the line was now complete
2023        int n = yyValidCharacters(stack, l, param->bShellAutoCorrect);
2024    
2025        // if auto correction is enabled, apply the auto corrected string to
2026        // intput/output string 'line'
2027        if (param->bShellAutoCorrect) {
2028            int nMin = (n < line.length()) ? n : line.length();
2029            line.replace(0, nMin, l.substr(0, nMin));
2030        }
2031    
2032        // generate an info string that will be sent to the LSCP shell for letting
2033        // it know which part is correct, which one is wrong, where is the cursor, etc.
2034        String result = line;
2035        result.insert(n <= result.length() ? n : result.length(), LSCP_SHK_GOOD_FRONT);
2036        int code = (n > line.length()) ? LSCP_SHU_COMPLETE : (n < line.length()) ?
2037                   LSCP_SHU_SYNTAX_ERR : LSCP_SHU_INCOMPLETE;
2038        result = "SHU:" + ToString(code) + ":" + result + LSCP_SHK_CURSOR;
2039        //if (n > line.length()) result += " [OK]";
2040    
2041        // get a clean parser stack to the last valid parse position
2042        // (due to the appended '\n' character above, and on syntax errors, the
2043        // symbol stack might be in undesired, i.e. reduced state)
2044        stack.clear();
2045        stack.push_back(0); // every Bison symbol stack starts with state zero
2046        l = line.substr(0, n);
2047        if (!l.empty()) yyValidCharacters(stack, l, param->bShellAutoCorrect);
2048    
2049        // generate auto completion suggestion (based on the current parser stack)
2050        std::vector<YYTYPE_INT16> stackCopy = stack; // make a copy, since yyAutoComplete() might alter the stack
2051        String sSuggestion = yyAutoComplete(stackCopy);
2052        if (!sSuggestion.empty()) result += LSCP_SHK_SUGGEST_BACK + sSuggestion;
2053    
2054        if (!possibilities) return result;
2055    
2056        // finally append all possible terminals and non-terminals according to
2057        // current parser state
2058        String notUsedHere;
2059        std::map<String,BisonSymbolInfo> expectedSymbols;
2060        walkAndFillExpectedSymbols(stack, expectedSymbols, notUsedHere);
2061        {
2062            // pretend to LSCP shell that the following terminal symbols were
2063            // non-terminal symbols (since they are not human visible for auto
2064            // completion on the shell's screen)
2065            std::set<String> specialNonTerminals;
2066            specialNonTerminals.insert("SP");
2067            specialNonTerminals.insert("CR");
2068            specialNonTerminals.insert("LF");
2069    
2070            String sPossibilities;
2071            int iNonTerminals = 0;
2072            int iTerminals    = 0;
2073            for (std::map<String,BisonSymbolInfo>::const_iterator it = expectedSymbols.begin();
2074                 it != expectedSymbols.end(); ++it)
2075            {
2076                if (!sPossibilities.empty()) sPossibilities += " | ";
2077                if (it->second.isTerminalSymbol && !specialNonTerminals.count(it->first)) {
2078                    sPossibilities += it->first;
2079                    iTerminals++;
2080                } else {
2081                    sPossibilities += "<" + it->first + ">";
2082                    iNonTerminals++;
2083                }
2084            }
2085            if (!sPossibilities.empty() && (iNonTerminals || iTerminals > 1)) {
2086                result += LSCP_SHK_POSSIBILITIES_BACK + sPossibilities;
2087            }
2088        }
2089    
2090    #if DEBUG_SHELL_INTERACTION
2091        printf("%s\n", result.c_str());
2092    #endif
2093    
2094        return result;
2095  }  }
2096    
2097  /**  /**
# Line 1025  void restart(yyparse_param_t* pparam, in Line 2101  void restart(yyparse_param_t* pparam, in
2101      bytes = 0;      bytes = 0;
2102      ptr   = 0;      ptr   = 0;
2103      sLastError = "";      sLastError = "";
2104        sParsed = "";
2105    }
2106    
2107  }  }

Legend:
Removed from v.1345  
changed lines
  Added in v.2528

  ViewVC Help
Powered by ViewVC