Files
GoldenCheetah/src/FileIO/JsonRideFile.l
Mark Liversedge 2fccbd0504 JsonRideFile XDATA support
.. added a new 'XDATA' element for the JsonRideFile and
   RideFile classes.

.. this allows ride file readers to extract and load any
   time series data that doesn't neccessarily fit into
   the usual data points.

.. this was added to support weather data from FIT files
   and also to support 3rd party merging data with the
   GC supported data.

.. ** IMPORTANT ** the XDATA segment is added at the END
   of the JSON format. So older parsers will fail to read
   but will have loaded all data already (i.e. they will
   fail gracefully enough)

   This means files with XDATA can be read by earlier
   versions of GC, but the XDATA will be discarded.
2016-06-19 10:25:03 +01:00

179 lines
6.3 KiB
Plaintext

%{
/*
* Copyright (c) 2010 Mark Liversedge (liversedge@gmail.com)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "JsonRideFile.h"
// we use stdio for reading from FILE *JsonRideFilein
// because thats what lex likes to do, and since we're
// reading files that seems ok anyway
#include <stdio.h>
// The parser defines the token values for us
// so lets include them before declaring the
// token patterns
#include "JsonRideFile_yacc.h"/* generated by the scanner */
// the options below tell flex to no bother with
// yywrap since we only ever read a single file
// anyway. And yyunput() isn't needed for our
// parser, we read in one pass with no swanky
// interactions
#define YYSTYPE QString
// Un-Escape special characters (JSON compliance)
static QString unprotect(char *string)
{
// sending UTF-8 to FLEX demands symetric conversion back to QString
QString string2 = QString::fromUtf8(string);
// this is a lexer string so it will be enclosed
// in quotes. Lets strip those first
QString s = string2.mid(1,string2.length()-2);
// does it end with a space (to avoid token conflict) ?
if (s.endsWith(" ")) s = s.mid(0, s.length()-1);
// now un-escape the control characters
s.replace("\\t", "\t"); // tab
s.replace("\\n", "\n"); // newline
s.replace("\\r", "\r"); // carriage-return
s.replace("\\b", "\b"); // backspace
s.replace("\\f", "\f"); // formfeed
s.replace("\\/", "/"); // solidus
s.replace("\\\"", "\""); // quote
s.replace("\\\\", "\\"); // backslash
return s;
}
// we reimplement these to remove compiler warnings
// about unused parameter (scanner) in the default
// implementations, which may freak out developers
void *JsonRideFilealloc (yy_size_t size , yyscan_t /*scanner*/)
{
return (void *) malloc( size );
}
void *JsonRideFilerealloc (void * ptr, yy_size_t size , yyscan_t /*scanner*/)
{
/* The cast to (char *) in the following accommodates both
* implementations that use char* generic pointers, and those
* that use void* generic pointers. It works with the latter
* because both ANSI C and C++ allow castless assignment from
* any pointer type to void*, and deal with argument conversions
* as though doing an assignment.
*/
return (void *) realloc( (char *) ptr, size );
}
void JsonRideFilefree (void * ptr , yyscan_t /*scanner*/)
{
free( (char *) ptr ); /* see JsonRideFilerealloc() for (char *) cast */
}
// replace this too, as a) it exits (!!)
// cannot shutup compiler warning on yy_fatal_error function tho :(
#define YY_FATAL_ERROR(msg) qDebug()<<msg;
%}
%option prefix="JsonRideFile"
%option never-interactive
%option noyyalloc
%option noyyrealloc
%option noyyfree
%option noyywrap
%option nounput
%option noinput
%option reentrant
%option bison-bridge
%%
\"RIDE\" return RIDE;
\"STARTTIME\" return STARTTIME;
\"RECINTSECS\" return RECINTSECS;
\"DEVICETYPE\" return DEVICETYPE;
\"IDENTIFIER\" return IDENTIFIER;
\"OVERRIDES\" return OVERRIDES;
\"TAGS\" return TAGS;
\"INTERVALS\" return INTERVALS;
\"NAME\" return NAME;
\"START\" return START;
\"STOP\" return STOP;
\"CALIBRATIONS\" return CALIBRATIONS;
\"VALUE\" return VALUE;
\"VALUES\" return VALUES;
\"XDATA\" return XDATA;
\"REFERENCES\" return REFERENCES;
\"SAMPLES\" return SAMPLES;
\"SECS\" return SECS;
\"KM\" return KM;
\"WATTS\" return WATTS;
\"NM\" return NM;
\"CAD\" return CAD;
\"KPH\" return KPH;
\"HR\" return HR;
\"ALT\" return ALTITUDE; // ALT clashes with qtnamespace.h:46
\"LAT\" return LAT;
\"LON\" return LON;
\"HEADWIND\" return HEADWIND;
\"SLOPE\" return SLOPE;
\"TEMP\" return TEMP;
\"LRBALANCE\" return LRBALANCE;
\"LTE\" return LTE;
\"RTE\" return RTE;
\"LPS\" return LPS;
\"RPS\" return RPS;
\"LPCO\" return LPCO;
\"RPCO\" return RPCO;
\"LPPB\" return LPPB;
\"RPPB\" return RPPB;
\"LPPE\" return LPPE;
\"RPPE\" return RPPE;
\"LPPPB\" return LPPPB;
\"RPPPB\" return RPPPB;
\"LPPPE\" return LPPPE;
\"RPPPE\" return RPPPE;
\"SMO2\" return SMO2;
\"THB\" return THB;
\"RCON\" return RCON;
\"RVERT\" return RVERT;
\"RCAD\" return RCAD;
[-+]?[0-9]+ { *yylval = QString::fromUtf8(yytext); return JS_INTEGER; }
[-+]?[0-9]+e-[0-9]+ { *yylval = QString::fromUtf8(yytext); return JS_FLOAT; }
[-+]?[0-9]+\.[-+e0-9]* { *yylval = QString::fromUtf8(yytext); return JS_FLOAT; }
\"([^\"]|\\\")*\" { *yylval = unprotect(yytext); return JS_STRING; } /* contains non-quotes or escaped-quotes */
[ \n\t\r] ; /* we just ignore whitespace */
. return yytext[0]; /* any other character, typically :, { or } */
%%
// Older versions of flex (prior to 2.5.9) do not have the destroy function
// Or We're not using GNU flex then we also won't have a destroy function
#if !defined(FLEX_SCANNER) || (YY_FLEX_MINOR_VERSION < 6 && YY_FLEX_SUBMINOR_VERSION < 9)
int JsonRideFilelex_destroy(void*) { return 0; }
#endif
void JsonRideFile_setString(QString p, void *scanner)
{
// internally work with UTF-8 encoding
// this works for FLEX, since the multi-byte characters only appear WITHIN a "String",
// but not as part of the grammar - this is important since a char in UTF-8 can have up to 4 bytes
JsonRideFile_scan_string(p.toUtf8().data(), scanner);
}