root/trunk/lib/ubasic/tokenizer.c @ 511

Revision 497, 15.5 KB (checked in by phyrephox, 5 years ago)

+ added dutch language file
+ added ubasic command: get_time. can be fed with 0 (returns seconds), 1 (minute), 2 (hour),3 (day) 4 (month) 5 (year) - command also exists in lua, though must be fed with CHARS
+ added ubasic command: get_mode - returns 0 in record mode, 1 in playback mode, it's that simple. useful for shutting of scripts that are meant to be run in a certain mode (like 99% of all available scripts). - someone needs to port that to lua, as i javent played around with that yet!
+ added ubasic commands: get_quality, get_resolution (return quality and resolution regardless of OS) & set_quality,set_resolution - for possible values see  http://chdk.wikia.com/wiki/PropertyCase (basically for quality you can 0-2, 2 being the worst, resolution can be set between 0 and 8, see the wiki) - needs porting to lua as well.
* changed 2 default settings in the conf: now "Hide OSD in playback" is enabled at default, also "disable saving raw while recording video" is enabled at default(S-eries)
* fixed some newline related warnings at compile time

Author's comment: Now everything should be at hand to be able to create true universal scripts. i'm thinking for example of fudgeys motion detection one, should run on digic II and III now, also on cams with and without moviebutton - all the commands are there. who is willing to write such a script? also please add the get_mode check in the beginning.

Line 
1/*
2 * Copyright (c) 2006, Adam Dunkels
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the author nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 */
30
31#if DEBUG
32#define DEBUG_PRINTF(...)  printf(__VA_ARGS__)
33#else
34#define DEBUG_PRINTF(...)
35#endif
36
37#ifdef TEST
38#include <string.h>
39#include <ctype.h>
40#endif
41
42#include "tokenizer.h"
43#include "stdlib.h"
44
45static char const *ptr, *nextptr;
46
47#define MAX_NUMLEN 6
48
49struct keyword_token {
50  const char *keyword;
51  int token;
52};
53
54static ubasic_token current_token = TOKENIZER_ERROR;
55static int current_line = 0;
56
57static const struct keyword_token keywords[] = {
58  {"<>",                                  TOKENIZER_NE},
59  {"<=",                                  TOKENIZER_LE},
60  {">=",                                  TOKENIZER_GE},
61  {"<",                           TOKENIZER_LT},
62  {">",                       TOKENIZER_GT},
63  {"not",                     TOKENIZER_LNOT},
64  {"or",                      TOKENIZER_LOR},
65  {"and",                     TOKENIZER_LAND},
66
67  {"let",                     TOKENIZER_LET},
68  {"if",                      TOKENIZER_IF},
69  {"then",                    TOKENIZER_THEN},
70  {"else",                    TOKENIZER_ELSE},
71  {"endif",                   TOKENIZER_ENDIF},
72  {"select",                  TOKENIZER_SELECT},
73  {"case_else",               TOKENIZER_CASE_ELSE},
74  {"case",                    TOKENIZER_CASE},
75  {"end_select",              TOKENIZER_END_SELECT},
76  {"for",                     TOKENIZER_FOR},
77  {"to",                      TOKENIZER_TO},
78  {"next",                    TOKENIZER_NEXT},
79  {"step",                    TOKENIZER_STEP},
80  {"do",                      TOKENIZER_DO},
81  {"until",                   TOKENIZER_UNTIL},
82  {"while",                   TOKENIZER_WHILE},
83  {"wend",                    TOKENIZER_WEND},
84  {"goto",                    TOKENIZER_GOTO},
85  {"gosub",                   TOKENIZER_GOSUB},
86  {"return",                  TOKENIZER_RETURN},
87  {"call",                    TOKENIZER_CALL},
88  {"rem",                     TOKENIZER_REM},
89  {"cls",                     TOKENIZER_CLS},
90  {"print_screen",            TOKENIZER_PRINT_SCREEN},
91  {"print",                   TOKENIZER_PRINT},
92  {"random",                  TOKENIZER_RANDOM},
93  {"click",                   TOKENIZER_CLICK},
94  {"playsound",                   TOKENIZER_PLAY_SOUND},
95  {"press",                   TOKENIZER_PRESS},
96  {"release",                 TOKENIZER_RELEASE},
97  //{"shot",                    TOKENIZER_SHOOT}, // for compatibility
98  {"shoot",                   TOKENIZER_SHOOT},
99  {"sleep",                   TOKENIZER_SLEEP},
100
101  /* WARNING due to tokenizer limitation longest match must be first */
102// GET 
103  {"get_av96",                TOKENIZER_GET_AV96},
104  {"get_av",                  TOKENIZER_GET_USER_AV_ID}, //FOR COMPATIBILITY
105  {"get_bv96",                TOKENIZER_GET_BV96},
106  {"get_display_mode",        TOKENIZER_GET_DISPLAY_MODE},
107  {"get_day_seconds",         TOKENIZER_GET_DAY_SECONDS},
108  {"get_disk_size",           TOKENIZER_GET_DISK_SIZE},
109  {"get_dof",                 TOKENIZER_GET_DOF},
110  {"get_far_limit",           TOKENIZER_GET_FAR_LIMIT},
111  {"get_free_disk_space",     TOKENIZER_GET_FREE_DISK_SPACE},
112  {"get_focus_mode",          TOKENIZER_GET_FOCUS_MODE},
113  {"get_focus",               TOKENIZER_GET_FOCUS},
114  {"get_hyp_dist",            TOKENIZER_GET_HYPERFOCAL_DIST},
115  {"get_iso_market",          TOKENIZER_GET_ISO_MARKET},
116  {"get_iso_mode",            TOKENIZER_GET_ISO_MODE},
117  {"get_iso_real",            TOKENIZER_GET_ISO_REAL},
118  {"get_iso",                 TOKENIZER_GET_ISO_MODE}, //FOR COMPATIBILITY
119  {"get_jpg_count",           TOKENIZER_GET_JPG_COUNT},
120  {"get_movie_status",        TOKENIZER_GET_MOVIE_STATUS},
121  {"get_mode",                                  TOKENIZER_GET_MODE},  // Returns 0 in recordmode, 1 in playmode
122  {"get_near_limit",          TOKENIZER_GET_NEAR_LIMIT},
123  {"get_propset",             TOKENIZER_GET_PROPSET},
124  {"get_prop",                TOKENIZER_GET_PROP},
125  {"get_quality",             TOKENIZER_GET_QUALITY},
126  {"get_raw_count",           TOKENIZER_GET_RAW_COUNT},
127  {"get_raw_nr",              TOKENIZER_GET_RAW_NR},
128  {"get_raw",                 TOKENIZER_GET_RAW},
129  {"get_resolution",          TOKENIZER_GET_RESOLUTION},
130  {"get_sv96",                TOKENIZER_GET_SV96},
131  {"get_temperature",         TOKENIZER_GET_TEMPERATURE},
132  {"get_tick_count",          TOKENIZER_GET_TICK_COUNT},
133  {"get_time",                                  TOKENIZER_GET_TIME},
134  {"get_tv96",                TOKENIZER_GET_TV96},
135  {"get_user_av_id",          TOKENIZER_GET_USER_AV_ID},
136  {"get_user_av96",           TOKENIZER_GET_USER_AV96},
137  {"get_user_tv_id",          TOKENIZER_GET_USER_TV_ID},
138  {"get_user_tv96",           TOKENIZER_GET_USER_TV96},
139  {"get_video_button",        TOKENIZER_GET_VIDEO_BUTTON},
140  {"get_vbatt",               TOKENIZER_GET_VBATT}, 
141  {"get_zoom_steps",          TOKENIZER_GET_ZOOM_STEPS},
142  {"get_zoom",                TOKENIZER_GET_ZOOM},
143  {"get_exp_count",           TOKENIZER_GET_EXP_COUNT},
144
145
146
147//SET 
148  {"set_av96_direct",         TOKENIZER_SET_AV96_DIRECT},
149  {"set_av_rel",              TOKENIZER_SET_USER_AV_BY_ID_REL}, //FOR COMPATIBILITY
150  {"set_av96",                TOKENIZER_SET_AV96},
151  {"set_av",                  TOKENIZER_SET_USER_AV_BY_ID}, //FOR COMPATIBILITY
152  {"set_focus",               TOKENIZER_SET_FOCUS},
153  {"set_iso_mode",            TOKENIZER_SET_ISO_MODE},
154  {"set_iso_real",            TOKENIZER_SET_ISO_REAL},
155  {"set_iso",                 TOKENIZER_SET_ISO_MODE}, //FOR COMPATIBILITY
156  {"set_led",                 TOKENIZER_SET_LED},
157  {"set_movie_status",        TOKENIZER_SET_MOVIE_STATUS}, 
158  {"set_nd_filter",           TOKENIZER_SET_ND_FILTER},
159  {"set_prop",                TOKENIZER_SET_PROP},
160  {"set_quality",                TOKENIZER_SET_QUALITY},
161  {"set_raw_nr",              TOKENIZER_SET_RAW_NR},
162  {"set_raw",                 TOKENIZER_SET_RAW},
163  {"set_resolution",          TOKENIZER_SET_RESOLUTION},
164    //{"set_shutter_speed",       TOKENIZER_SET_SHUTTER_SPEED},
165  {"set_sv96",                    TOKENIZER_SET_SV96},
166  {"set_tv96_direct",         TOKENIZER_SET_TV96_DIRECT},
167  {"set_tv_rel",              TOKENIZER_SET_USER_TV_BY_ID_REL}, //FOR COMPATIBILITY
168  {"set_tv96",                TOKENIZER_SET_TV96},
169  {"set_tv",                  TOKENIZER_SET_USER_TV_BY_ID}, //FOR COMPATIBILITY
170  {"set_user_av_by_id_rel",   TOKENIZER_SET_USER_AV_BY_ID_REL},
171  {"set_user_av_by_id",       TOKENIZER_SET_USER_AV_BY_ID},
172  {"set_user_av96",           TOKENIZER_SET_USER_AV96},
173  {"set_user_tv_by_id_rel",   TOKENIZER_SET_USER_TV_BY_ID_REL},
174  {"set_user_tv_by_id",       TOKENIZER_SET_USER_TV_BY_ID},
175  {"set_user_tv96",           TOKENIZER_SET_USER_TV96},
176  {"set_zoom_speed",          TOKENIZER_SET_ZOOM_SPEED},
177  {"set_zoom_rel",            TOKENIZER_SET_ZOOM_REL},
178  {"set_zoom",                TOKENIZER_SET_ZOOM},
179 
180 
181  {"wait_click",              TOKENIZER_WAIT_CLICK},
182  {"is_pressed",              TOKENIZER_IS_PRESSED},
183  {"is_key",                  TOKENIZER_IS_KEY},
184 
185  {"wheel_right",             TOKENIZER_WHEEL_RIGHT},
186  {"wheel_left",              TOKENIZER_WHEEL_LEFT},
187 
188  {"@title",                  TOKENIZER_REM},
189  {"@param",                  TOKENIZER_REM},
190  {"@default",                TOKENIZER_REM},
191
192  {"md_detect_motion",        TOKENIZER_MD_DETECT_MOTION},
193  {"md_get_cell_diff",        TOKENIZER_MD_GET_CELL_DIFF},
194  {"autostarted",             TOKENIZER_SCRIPT_AUTOSTARTED},
195  {"get_autostart",           TOKENIZER_GET_SCRIPT_AUTOSTART},
196  {"set_autostart",           TOKENIZER_SET_SCRIPT_AUTOSTART},
197  {"get_usb_power",           TOKENIZER_GET_USB_POWER},
198  {"exit_alt",                TOKENIZER_EXIT_ALT},
199  {"shut_down",               TOKENIZER_SHUT_DOWN},
200
201  {"get_shooting",            TOKENIZER_GET_SHOOTING},
202  {"get_drive_mode",          TOKENIZER_GET_DRIVE_MODE},
203  {"get_flash_mode",          TOKENIZER_GET_FLASH_MODE},
204  {"get_flash_ready",         TOKENIZER_GET_FLASH_READY},
205  {"get_IS_mode",             TOKENIZER_GET_IS_MODE},
206  {"set_ev",                  TOKENIZER_SET_EV},
207  {"get_ev",                  TOKENIZER_GET_EV},
208  {"get_orientation_sensor",  TOKENIZER_GET_ORIENTATION_SENSOR},
209  {"get_nd_present",          TOKENIZER_GET_ND_PRESENT},
210  {"get_histo_range",         TOKENIZER_GET_HISTO_RANGE},
211   {"shot_histo_enable",       TOKENIZER_SHOT_HISTO_ENABLE},
212 
213  {"end",                     TOKENIZER_END},
214
215  {NULL,                      TOKENIZER_ERROR}
216};
217
218/*---------------------------------------------------------------------------*/
219static int
220singlechar(void)
221{
222  if(*ptr == '\n') {
223    return TOKENIZER_CR;
224  } else if(*ptr == ',') {
225    return TOKENIZER_COMMA;
226  } else if(*ptr == ';') {
227    return TOKENIZER_SEMICOLON;
228  } else if(*ptr == '+') {
229    return TOKENIZER_PLUS;
230  } else if(*ptr == '-') {
231    return TOKENIZER_MINUS;
232  } else if(*ptr == '&') {
233    return TOKENIZER_AND;
234  } else if(*ptr == '|') {
235    return TOKENIZER_OR;
236  } else if(*ptr == '^') {
237    return TOKENIZER_XOR;
238  } else if(*ptr == '*') {
239    return TOKENIZER_ASTR;
240  } else if(*ptr == '/') {
241    return TOKENIZER_SLASH;
242  } else if(*ptr == '%') {
243    return TOKENIZER_MOD;
244  } else if(*ptr == '(') {
245    return TOKENIZER_LEFTPAREN;
246  } else if(*ptr == ')') {
247    return TOKENIZER_RIGHTPAREN;
248  } else if(*ptr == '=') {
249    return TOKENIZER_EQ;
250  }
251  return 0;
252}
253/*---------------------------------------------------------------------------*/
254static int
255get_next_token(void)
256{
257  struct keyword_token const *kt;
258  int i;
259
260  DEBUG_PRINTF("get_next_token(): '%s'\n", ptr);
261
262  // eat all whitespace
263  while(*ptr == ' ' || *ptr == '\t' || *ptr == '\r') ptr++;
264
265  if(*ptr == 0) {
266    return TOKENIZER_ENDOFINPUT;
267  }
268 
269  if(isdigit(*ptr)) {
270    for(i = 0; i < (MAX_NUMLEN+1); ++i) {
271      if(!isdigit(ptr[i])) {
272        if(i > 0) {
273          nextptr = ptr + i;
274          return TOKENIZER_NUMBER;
275        } else {
276          DEBUG_PRINTF("get_next_token: error due to too short number\n");
277          return TOKENIZER_ERROR;
278        }
279      }
280      if(!isdigit(ptr[i])) {
281        DEBUG_PRINTF("get_next_token: error due to malformed number\n");
282        return TOKENIZER_ERROR;
283      }
284    }
285    DEBUG_PRINTF("get_next_token: error due to too long number\n");
286    return TOKENIZER_ERROR;
287  } else if(*ptr == ':') {
288    // label
289    nextptr = ptr;
290    do {
291      ++nextptr;
292    } while(*nextptr != ' ' && *nextptr != '\r' && *nextptr != '\n' && *nextptr != '\t');
293    return TOKENIZER_LABEL;
294  } else if((i=singlechar()) != 0) {
295    if (i == TOKENIZER_CR){
296      // move to next line, and skip all following empty lines as well
297      while (singlechar() == TOKENIZER_CR)
298      {
299        current_line++;
300        ptr++;
301        // eat all whitespace
302        while(*ptr == ' ' || *ptr == '\t' || *ptr == '\r') ptr++;
303      };
304      ptr--;
305      // dangelo: now the last char might point to a whitespace instead of
306      // a CR. I hope that doesn't break anything.
307    }
308    nextptr = ptr + 1;
309    return i;
310  } else if(*ptr == '"') {
311    nextptr = ptr;
312    do {
313      ++nextptr;
314    } while(*nextptr != '"');
315    ++nextptr;
316    return TOKENIZER_STRING;
317  } else {
318    for(kt = keywords; kt->keyword != NULL; ++kt) {
319      if(strncmp(ptr, kt->keyword, strlen(kt->keyword)) == 0) {
320        nextptr = ptr + strlen(kt->keyword);
321        if (kt->token == TOKENIZER_REM) {
322           while(*nextptr != 0 && *nextptr != '\r' && *nextptr != '\n') ++nextptr;
323        }
324        return kt->token;
325      }
326    }
327  }
328
329  if((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z')) {
330    nextptr = ptr + 1;
331    return TOKENIZER_VARIABLE;
332  }
333
334 
335  return TOKENIZER_ERROR;
336}
337/*---------------------------------------------------------------------------*/
338void
339tokenizer_init(const char *program)
340{
341  ptr = program;
342  current_line = 1;
343  current_token = get_next_token();
344}
345/*---------------------------------------------------------------------------*/
346int
347tokenizer_token(void)
348{
349  return current_token;
350}
351/*---------------------------------------------------------------------------*/
352void
353tokenizer_next(void)
354{
355
356  if(tokenizer_finished()) {
357    return;
358  }
359
360  DEBUG_PRINTF("tokenizer_next: %p\n", nextptr);
361  ptr = nextptr;
362  while((*ptr == ' ') || (*ptr == '\t')) {
363    ++ptr;
364  }
365  current_token = get_next_token();
366  DEBUG_PRINTF("tokenizer_next: '%s' %d\n", ptr, current_token);
367  return;
368}
369/*---------------------------------------------------------------------------*/
370int
371tokenizer_num(void)
372{
373  return atoi(ptr);
374}
375/*---------------------------------------------------------------------------*/
376void
377tokenizer_string(char *dest, int len)
378{
379  char *string_end;
380  int string_len;
381 
382  if(tokenizer_token() != TOKENIZER_STRING) {
383    return;
384  }
385  string_end = strchr(ptr + 1, '"');
386  if(string_end == NULL) {
387    return;
388  }
389  string_len = string_end - ptr - 1;
390  if(len < string_len) {
391    string_len = len;
392  }
393  memcpy(dest, ptr + 1, string_len);
394  dest[string_len] = 0;
395}
396/*---------------------------------------------------------------------------*/
397void
398tokenizer_label(char *dest, int len)
399{
400  char *string_end;
401  int string_len;
402 
403  if(tokenizer_token() != TOKENIZER_LABEL) {
404    return;
405  }
406  // allow string \r, \n, tabulation and space to end labels
407  string_end = strpbrk(ptr + 1, " \t\r\n");
408
409  if(string_end == NULL) {
410    return;
411  }
412  string_len = string_end - ptr - 1;
413  if(len < string_len) {
414    string_len = len;
415  }
416  memcpy(dest, ptr + 1, string_len);
417  dest[string_len] = 0;
418}
419/*---------------------------------------------------------------------------*/
420void
421tokenizer_error_print(void)
422{
423  DEBUG_PRINTF("tokenizer_error_print: '%s'\n", ptr);
424}
425/*---------------------------------------------------------------------------*/
426int
427tokenizer_finished(void)
428{
429  return *ptr == 0 || current_token == TOKENIZER_ENDOFINPUT;
430}
431/*---------------------------------------------------------------------------*/
432int
433tokenizer_variable_num(void)
434{
435  return *ptr - (*ptr>='a'?'a':('A'-26));
436}
437/*---------------------------------------------------------------------------*/
438int tokenizer_line_number(void)
439{
440  return current_line;
441}
Note: See TracBrowser for help on using the browser.