/[svn]/linuxsampler/trunk/src/network/lscp.y
ViewVC logotype

Contents of /linuxsampler/trunk/src/network/lscp.y

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2534 - (show annotations) (download)
Sun Mar 9 21:34:03 2014 UTC (10 years, 1 month ago) by schoenebeck
File size: 113878 byte(s)
* LSCP shell (WIP): Added initial support for built-in LSCP reference
  documentation, which will automatically show the relevant LSCP reference
  section on screen as soon as one specific LSCP command was detected while
  typing on the command line.
* Bumped version (1.0.0.svn37).

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

  ViewVC Help
Powered by ViewVC