--- linuxsampler/trunk/src/scriptvm/scanner.l 2016/12/15 12:47:45 3054 +++ linuxsampler/trunk/src/scriptvm/scanner.l 2019/08/27 21:36:53 3573 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016 Christian Schoenebeck and Andreas Persson + * Copyright (c) 2014-2017 Christian Schoenebeck and Andreas Persson * * http://www.linuxsampler.org * @@ -76,6 +76,13 @@ if (nl) yycolumn = countCharsPastLastNewLine(yytext); \ } +// if compiled for debugging, throw an exception instead of exiting on fatal +// lexer errors (so the debugger may pause with the appropriate back trace) +#if DEBUG +# include +# define YY_FATAL_ERROR(msg) throw std::runtime_error(msg) +#endif + %} /* use Flex's built-in support for line numbers @@ -101,7 +108,9 @@ %x PREPROC_SET_COND PREPROC_RESET_COND PREPROC_IF PREPROC_IF_NOT PREPROC_BODY_EAT PREPROC_PRE_BODY_USE PREPROC_PRE_BODY_EAT DIGIT [0-9] -ID [a-zA-Z0-9_]+ +ID [a-zA-Z][a-zA-Z0-9_]* +METRIC (k|h|(da)|d|c|m|u) +UNIT (s|(Hz)|B) %% @@ -112,14 +121,111 @@ } {DIGIT}+ { - yylval->iValue = atoi(yytext); + if (sizeof(vmint) < 8) + yylval->iValue = atoi(yytext); + else + yylval->iValue = atoll(yytext); return INTEGER; } - /* there is currently no support for floating point numbers in NKSP yet */ - /*{DIGIT}+"."{DIGIT}* { - printf("A float: %s (%g)\n", yytext, atof(yytext)); - }*/ +{DIGIT}+"."{DIGIT}+ { + yylval->fValue = atof(yytext); + return REAL; +} + +{DIGIT}+({METRIC}{1,2}|({METRIC}{0,2}{UNIT}?)) { + int pos = 0; + + // parse number portion + vmint value = 0; + for (; yytext[pos] >= '0' && yytext[pos] <= '9'; ++pos) { + value *= 10; + value += yytext[pos] - '0'; + } + yylval->iUnitValue.iValue = value; + + // parse metric prefix portion + for (int i = 0; i < 2; ++i, ++pos) { + switch (yytext[pos]) { + case 'k': yylval->iUnitValue.prefix[i] = VM_KILO; continue; + case 'h': yylval->iUnitValue.prefix[i] = VM_HECTO; continue; + case 'c': yylval->iUnitValue.prefix[i] = VM_CENTI; continue; + case 'm': yylval->iUnitValue.prefix[i] = VM_MILLI; continue; + case 'u': yylval->iUnitValue.prefix[i] = VM_MICRO; continue; + case 'd': + if (yytext[pos+1] == 'a') { + yylval->iUnitValue.prefix[i] = VM_DECA; + ++pos; + } else { + yylval->iUnitValue.prefix[i] = VM_DECI; + } + continue; + default: + yylval->iUnitValue.prefix[i] = VM_NO_PREFIX; + goto parseIntStdUnit; + } + } + + parseIntStdUnit: + + // parse standard measurement unit + switch (yytext[pos]) { + case 's': yylval->iUnitValue.unit = VM_SECOND; break; + case 'H': yylval->iUnitValue.unit = VM_HERTZ; break; + case 'B': yylval->iUnitValue.unit = VM_BEL; break; + default: yylval->iUnitValue.unit = VM_NO_UNIT; break; + } + + return INTEGER_UNIT; +} + +{DIGIT}+"."{DIGIT}+({METRIC}{1,2}|({METRIC}{0,2}{UNIT}?)) { + int pos = 0; + + // parse number portion + for (; (yytext[pos] >= '0' && yytext[pos] <= '9') || yytext[pos] == '.'; ++pos) { + } + { + const char tmp = yytext[pos]; + yytext[pos] = 0; // mark temporary end of string + yylval->fUnitValue.fValue = atof(yytext); + yytext[pos] = tmp; // restore + } + + // parse metric prefix portion + for (int i = 0; i < 2; ++i, ++pos) { + switch (yytext[pos]) { + case 'k': yylval->fUnitValue.prefix[i] = VM_KILO; continue; + case 'h': yylval->fUnitValue.prefix[i] = VM_HECTO; continue; + case 'c': yylval->fUnitValue.prefix[i] = VM_CENTI; continue; + case 'm': yylval->fUnitValue.prefix[i] = VM_MILLI; continue; + case 'u': yylval->fUnitValue.prefix[i] = VM_MICRO; continue; + case 'd': + if (yytext[pos+1] == 'a') { + yylval->fUnitValue.prefix[i] = VM_DECA; + ++pos; + } else { + yylval->fUnitValue.prefix[i] = VM_DECI; + } + continue; + default: + yylval->fUnitValue.prefix[i] = VM_NO_PREFIX; + goto parseRealStdUnit; + } + } + + parseRealStdUnit: + + // parse standard measurement unit + switch (yytext[pos]) { + case 's': yylval->fUnitValue.unit = VM_SECOND; break; + case 'H': yylval->fUnitValue.unit = VM_HERTZ; break; + case 'B': yylval->fUnitValue.unit = VM_BEL; break; + default: yylval->fUnitValue.unit = VM_NO_UNIT; break; + } + + return REAL_UNIT; +} /* Preprocessor statement: SET_CONDITION(name) */ @@ -176,13 +282,21 @@ */ <*>"USE_CODE_IF"[ \t]*"(" { - //printf("USE_CODE_IF\n"); + //printf("{%s}\n", yytext); yy_push_state(PREPROC_IF, yyscanner); } +"USE_CODE_IF"[ \t]*"("{ID}")" { + //printf("[EAT{%s}\n", yytext); + yy_push_state(PREPROC_BODY_EAT, yyscanner); +} <*>"USE_CODE_IF_NOT"[ \t]*"(" { //printf("USE_CODE_IF_NOT\n"); yy_push_state(PREPROC_IF_NOT, yyscanner); } +"USE_CODE_IF_NOT"[ \t]*"("{ID}")" { + //printf("[EAT{%s}\n", yytext); + yy_push_state(PREPROC_BODY_EAT, yyscanner); +} {ID} { //printf("preproc use code if '%s'\n", yytext); yy_pop_state(yyscanner); @@ -204,19 +318,22 @@ yy_push_state(PREPROC_BODY_USE, yyscanner); } [ \t]*")" { - //printf("PREPROCESSOR EAT : \n"); + //printf("PREPROCESSOR EAT : {%s}\n", yytext); yy_pop_state(yyscanner); yy_push_state(PREPROC_BODY_EAT, yyscanner); } -<*>.*"END_USE_CODE" { +"END_USE_CODE" { //printf("-->END_USE_CODE\n"); yy_pop_state(yyscanner); } [ \t\r\n]* { /* eat up code block filtered out by preprocessor */ + //printf("PREPROCESSOR EAT2 : {%s}\n", yytext); processLocation(); } .* { /* eat up code block filtered out by preprocessor */ - processLocation(); + //printf("PREPROCESSOR EAT3 : {%s}\n", yytext); + yyextra->addPreprocessorComment(yylloc->first_line, yylloc->last_line, + yylloc->first_column+1, yylloc->last_column+1); } @@ -248,12 +365,13 @@ "mod" return MOD; "function" return FUNCTION; "call" return CALL; +"synchronized" return SYNCHRONIZED; -[&,()[\]<>=*+#/-] { +[&,!()[\]<>=*+#\/-] { return *yytext; } -("$"|"@"|"%"){ID} { +("$"|"@"|"%"|"~"|"?"){ID} { yylval->sValue = strdup(yytext); return VARIABLE; } @@ -278,7 +396,10 @@ [ \t\r]+ /* eat up whitespace */ -. printf( "Unrecognized character: '%s' (line %d, column %d)\n", yytext, yylineno, yycolumn); +. { + printf( "Unrecognized character: '%s' (line %d, column %d)\n", yytext, yylineno, yycolumn); + return UNKNOWN_CHAR; +} %%