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

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

  ViewVC Help
Powered by ViewVC