PageRenderTime 135ms CodeModel.GetById 3ms app.highlight 119ms RepoModel.GetById 1ms app.codeStats 0ms

/xbmc/visualizations/XBMCProjectM/libprojectM/Parser.cpp

http://github.com/xbmc/xbmc
C++ | 2577 lines | 1656 code | 566 blank | 355 comment | 649 complexity | a03b8c0b72e06072b3dab5840c0adff0 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/**
   2 * projectM -- Milkdrop-esque visualisation SDK
   3 * Copyright (C)2003-2004 projectM Team
   4 *
   5 * This library is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU
   7* License as published by the Free Software Foundation; either
   8 * version 2.1 of the License, or (at your option) any later version.
   9 *
  10 * This library is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 * Lesser General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU Lesser General Public
  16 * License along with this library; if not, write to the Free Software
  17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 * See 'LICENSE.txt' included within this release
  19 *
  20 */
  21/* parser.c */
  22
  23#include <stdio.h>
  24#include <string>
  25#include <cstring>
  26#include <iostream>
  27#include <stdlib.h>
  28
  29#include "Common.hpp"
  30#include "fatal.h"
  31
  32#include "CustomWave.hpp"
  33#include "CustomShape.hpp"
  34#include "Expr.hpp"
  35#include "Eval.hpp"
  36#include "Func.hpp"
  37#include "InitCond.hpp"
  38#include "Param.hpp"
  39#include "Preset.hpp"
  40#include "Parser.hpp"
  41#include "PerFrameEqn.hpp"
  42#include "PerPixelEqn.hpp"
  43#include <map>
  44#include "ParamUtils.hpp"
  45
  46#include "wipemalloc.h"
  47#include <iostream>
  48#include <sstream>
  49#include "BuiltinFuncs.hpp"
  50
  51/* Grabs the next token from the file. The second argument points
  52   to the raw string */
  53
  54line_mode_t Parser::line_mode;
  55CustomWave *Parser::current_wave;
  56CustomShape *Parser::current_shape;
  57int Parser::string_line_buffer_index;
  58char Parser::string_line_buffer[STRING_LINE_SIZE];
  59unsigned int Parser::line_count;
  60int Parser::per_frame_eqn_count;
  61int Parser::per_frame_init_eqn_count;
  62int Parser::last_custom_wave_id;
  63int Parser::last_custom_shape_id;
  64char Parser::last_eqn_type[MAX_TOKEN_SIZE];
  65int Parser::last_token_size;
  66
  67std::string Parser::lastLinePrefix("");
  68
  69#define white_space(c) ((c) == ' ' || (c) == '\t')
  70#define valid_digit(c) ((c) >= '0' && (c) <= '9')
  71#define end_char(c) ((c) == '\0' || (c) == '\r')
  72#define math_char(c) ((c) == '+' || (c) == '-'|| (c) == '.' || (c) == 'e'|| (c) == 'E' )
  73
  74double fastatof (const char *p, bool &b_validformat)
  75{
  76    //check if it is a valid float format (only basic checking with no sequence )
  77    const char *p1=p;
  78    while (!end_char(*p1) && ((math_char(*p1) || valid_digit(*p1))))
  79      p1 += 1;
  80    if (!end_char(*p1) || p1 == p)
  81    {
  82      b_validformat = false;
  83      return 0;
  84    }
  85    b_validformat = true;
  86
  87    int frac = 0;
  88    double sign, value, scale;
  89
  90    // Skip leading white space, if any.
  91    while (white_space(*p) ) {
  92        p += 1;
  93    }
  94
  95    // Get sign, if any.
  96    sign = 1.0;
  97    if (*p == '-') {
  98        sign = -1.0;
  99        p += 1;
 100    } else if (*p == '+') {
 101        p += 1;
 102    }
 103
 104    // Get digits before decimal point or exponent, if any.
 105    value = 0.0;
 106    while (valid_digit(*p)) {
 107        value = value * 10.0 + (*p - '0');
 108        p += 1;
 109    }
 110
 111    // Get digits after decimal point, if any.
 112    if (*p == '.') {
 113        double pow10 = 10.0;
 114        p += 1;
 115        while (valid_digit(*p)) {
 116            value += (*p - '0') / pow10;
 117            pow10 *= 10.0;
 118            p += 1;
 119        }
 120    }
 121
 122    // Handle exponent, if any.
 123    scale = 1.0;
 124    if ((*p == 'e') || (*p == 'E')) {
 125        unsigned int expon;
 126        p += 1;
 127
 128        // Get sign of exponent, if any.
 129        frac = 0;
 130        if (*p == '-') {
 131            frac = 1;
 132            p += 1;
 133        } else if (*p == '+') {
 134            p += 1;
 135        }
 136
 137        // Get digits of exponent, if any.
 138        expon = 0;
 139        while (valid_digit(*p)) {
 140            expon = expon * 10 + (*p - '0');
 141            p += 1;
 142        }
 143        if (expon > 308) expon = 308;
 144
 145        // Calculate scaling factor.
 146        while (expon >= 50) { scale *= 1E50; expon -= 50; }
 147        while (expon >=  8) { scale *= 1E8;  expon -=  8; }
 148        while (expon >   0) { scale *= 10.0; expon -=  1; }
 149    }
 150
 151    // Return signed and scaled floating point result.
 152    return sign * (frac ? (value / scale) : (value * scale));
 153}
 154
 155bool Parser::tokenWrapAroundEnabled(false);
 156
 157token_type Parser::parseToken(std::istream &  fs, char * string)
 158{
 159
 160  char c;
 161  int i;
 162
 163  if (string != NULL)
 164    memset(string, 0, MAX_TOKEN_SIZE);
 165
 166
 167  /* Loop until a delimiter is found, or the maximum string size is found */
 168  for (i = 0; i < MAX_TOKEN_SIZE;i++)
 169  {
 170    //c = fgetc(fs);
 171    if (!fs || fs.eof())
 172      c = EOF;
 173    else
 174      c = fs.get();
 175
 176    last_token_size++;
 177    /* If the string line buffer is full, quit */
 178    if (string_line_buffer_index == (STRING_LINE_SIZE - 1))
 179      return tStringBufferFilled;
 180
 181    /* Otherwise add this character to the string line buffer */
 182    string_line_buffer[string_line_buffer_index++] = tolower(c);
 183    /* Now interpret the character */
 184    switch (c)
 185    {
 186    case '+':
 187      return tPlus;
 188    case '-':
 189      return tMinus;
 190    case '%':
 191      return tMod;
 192    case '/':
 193
 194      /* check for line comment here */
 195      if (!fs || fs.eof())
 196        c = EOF;
 197      else
 198        c = fs.get();
 199      if (c == '/')
 200      {
 201        while (true)
 202        {
 203          if (!fs || fs.eof())
 204            c = EOF;
 205          else
 206            c = fs.get();
 207          if (c == EOF)
 208          {
 209            line_mode = UNSET_LINE_MODE;
 210            return tEOF;
 211          }
 212          if (c == '\n')
 213          {
 214            line_mode = UNSET_LINE_MODE;
 215            return tEOL;
 216          }
 217        }
 218
 219      }
 220
 221      /* Otherwise, just a regular division operator */
 222      fs.unget();
 223      return tDiv;
 224    case '*':
 225      return tMult;
 226    case '|':
 227      return tOr;
 228    case '&':
 229      return tAnd;
 230    case '(':
 231      return tLPr;
 232    case ')':
 233      return tRPr;
 234    case '[':
 235      return tLBr;
 236    case ']':
 237      return tRBr;
 238    case '=':
 239      return tEq;
 240    case '\n':
 241      line_count++;
 242      /// @note important hack implemented here to handle "wrap around tokens"
 243      // In particular: "per_frame_1=x=t+1.\nper_frame_2=37 + 5;" implies
 244      // "per_frame_1=x=t+1.37 + 5;". Thus, we have a global flag to determine
 245      // if "token wrap mode" is enabled. If so, we consider a token *continuing*
 246      // to the next line, but only attaching to the token buffer anything following
 247      // the first equals sign on that line.
 248      //
 249      // We can safely assume the next line must be part of the token if we allow the
 250      // semi colon to be a guaranteed delimiter in the grammar for all equation-based lines.
 251      // This IS NO LONGER assumed here. Instead, we check if the next line prefix
 252      // matches with the previous line prefix. If it passes a simple comparison, we wrap around.
 253
 254      if (tokenWrapAroundEnabled)
 255      {
 256	std::ostringstream buffer;
 257
 258        if (PARSE_DEBUG) std::cerr << "token wrap! line " << line_count << std::endl;
 259        while (c != '=')
 260        {
 261
 262          if (!fs || fs.eof())
 263          {
 264            line_count = 1;
 265            line_mode = UNSET_LINE_MODE;
 266        if (PARSE_DEBUG)     std::cerr << "token wrap: end of file" << std::endl;
 267            return tEOF;
 268          }
 269
 270          else {
 271	    c = fs.get();
 272	    if ( c != '=')
 273            	buffer << c;
 274	}
 275
 276        }
 277        if (PARSE_DEBUG) std::cerr << "parseToken: parsed away equal sign, line prefix is \""  << buffer.str() 
 278		<< "\"" << std::endl;
 279        --i;
 280
 281	if (!wrapsToNextLine(buffer.str())) {
 282		tokenWrapAroundEnabled = false;
 283		int buf_size = (int)buffer.str().length();
 284		// <= to also remove equal sign parsing from stream
 285		for (int k = 0; k <= buf_size; k++) {
 286			if (fs)					
 287				fs.unget();
 288			else
 289				abort();
 290		}
 291		return tEOL;
 292	}
 293		
 294	
 295        //   if (fs && fs.get() == '\n') {
 296        //     line_mode = UNSET_LINE_MODE;
 297        //	return tEOL;
 298        //    } else if (fs)
 299        //fs.unget();
 300
 301        break;
 302      }
 303
 304
 305      line_mode = UNSET_LINE_MODE;
 306      return tEOL;
 307    case ',':
 308      return tComma;
 309    case ';':
 310      tokenWrapAroundEnabled = false;
 311      if (PARSE_DEBUG) std::cerr << "token wrap around = false (LINE " << line_count << ")" << std::endl;
 312      return tSemiColon;
 313    case ' ': /* space, skip the character */
 314      i--;
 315      break;
 316    case EOF:
 317      line_count = 1;
 318      line_mode = UNSET_LINE_MODE;
 319      return tEOF;
 320
 321    case '\r':
 322      i--;
 323      break;
 324    default:
 325
 326      if (string != NULL)
 327      {
 328	/// @bug remove this nonsense
 329        if (c == '\r')
 330        {
 331          std::cerr << "R" << std::endl;
 332          abort();
 333        }
 334        if (c == '\b')
 335        {
 336          std::cerr << "B" << std::endl;
 337          abort();
 338        }
 339        string[i] = tolower(c);
 340        //string[i+1] = 0;
 341        //std::cerr << "string is \n\"" << string << "\"" << std::endl;
 342      }
 343    }
 344
 345  }
 346
 347  /* String reached maximum length, return special token error */
 348  return tStringTooLong;
 349
 350}
 351
 352/* Parse input in the form of "exp, exp, exp, ...)"
 353   Returns a general expression list */
 354
 355GenExpr **Parser::parse_prefix_args(std::istream &  fs, int num_args, Preset * preset)
 356{
 357
 358  int i, j;
 359  GenExpr ** expr_list; /* List of arguments to function */
 360  GenExpr * gen_expr;
 361
 362  /* Malloc the expression list */
 363  expr_list =  (GenExpr**)wipemalloc(sizeof(GenExpr*)*num_args);
 364
 365  /* Malloc failed */
 366  if (expr_list == NULL)
 367    return NULL;
 368
 369
 370  i = 0;
 371
 372  while (i < num_args)
 373  {
 374    //if (PARSE_DEBUG) printf("parse_prefix_args: parsing argument %d...\n", i+1);
 375    /* Parse the ith expression in the list */
 376    if ((gen_expr = parse_gen_expr(fs, NULL, preset)) == NULL)
 377    {
 378      //if (PARSE_DEBUG) printf("parse_prefix_args: failed to get parameter # %d for function (LINE %d)\n", i+1, line_count);
 379      for (j = 0; j < i; j++)
 380        delete expr_list[j];
 381      free(expr_list);
 382      expr_list = NULL;
 383      return NULL;
 384    }
 385    /* Assign entry in expression list */
 386    expr_list[i++] = gen_expr;
 387  }
 388
 389  //if (PARSE_DEBUG) printf("parse_prefix_args: finished parsing %d arguments (LINE %d)\n", num_args, line_count);
 390  /* Finally, return the resulting expression list */
 391  return expr_list;
 392}
 393
 394/* Parses a comment at the top of the file. Stops when left bracket is found */
 395int Parser::parse_top_comment(std::istream &  fs)
 396{
 397
 398  char string[MAX_TOKEN_SIZE];
 399  token_type token;
 400
 401  /* Process tokens until left bracket is found */
 402  while ((token = parseToken(fs, string)) != tLBr)
 403  {
 404    if (token == tEOF)
 405      return PROJECTM_PARSE_ERROR;
 406  }
 407
 408  /* Done, return success */
 409  return PROJECTM_SUCCESS;
 410}
 411
 412/* Right Bracket is parsed by this function.
 413   puts a new string into name */
 414int Parser::parse_preset_name(std::istream &  fs, char * name)
 415{
 416
 417  token_type token;
 418
 419  if (name == NULL)
 420    return PROJECTM_FAILURE;
 421
 422  if ((token = parseToken(fs, name)) != tRBr)
 423    return PROJECTM_PARSE_ERROR;
 424
 425  return PROJECTM_SUCCESS;
 426}
 427
 428
 429/* Parses per pixel equations */
 430int Parser::parse_per_pixel_eqn(std::istream &  fs, Preset * preset, char * init_string)
 431{
 432
 433
 434  char string[MAX_TOKEN_SIZE];
 435  GenExpr * gen_expr;
 436
 437
 438  if (init_string != 0)
 439  {
 440    strncpy(string, init_string, strlen(init_string));
 441  }
 442  else
 443  {
 444
 445    if (parseToken(fs, string) != tEq)
 446    { /* parse per pixel operator name */
 447      return PROJECTM_PARSE_ERROR;
 448    }
 449  }
 450
 451  /* Parse right side of equation as an expression */
 452  if ((gen_expr = parse_gen_expr(fs, NULL, preset)) == NULL)
 453  {
 454    return PROJECTM_PARSE_ERROR;
 455  }
 456
 457  /* Add the per pixel equation */
 458  if (preset->add_per_pixel_eqn(string, gen_expr) < 0)
 459  {
 460    if (PARSE_DEBUG)
 461    {
 462
 463    }
 464    delete gen_expr;
 465    return PROJECTM_PARSE_ERROR;
 466  }
 467
 468  return PROJECTM_SUCCESS;
 469}
 470
 471/* Parses an equation line, this function is way too big, should add some helper functions */
 472int Parser::parse_line(std::istream &  fs, Preset * preset)
 473{
 474
 475  char eqn_string[MAX_TOKEN_SIZE];
 476  token_type token;
 477  InitCond * init_cond;
 478  PerFrameEqn * per_frame_eqn;
 479
 480  /* Clear the string line buffer */
 481  memset(string_line_buffer, 0, STRING_LINE_SIZE);
 482  string_line_buffer_index = 0;
 483 
 484  tokenWrapAroundEnabled = false;
 485
 486  token = parseToken( fs, eqn_string );
 487  switch (token )
 488  {
 489
 490    /* Invalid Cases */
 491  case tRBr:
 492  case tLPr:
 493  case tRPr:
 494  case tComma:
 495  case tLBr:
 496  case tPlus:
 497  case tMinus:
 498  case tMod:
 499  case tMult:
 500  case tOr:
 501  case tAnd:
 502  case tDiv:
 503
 504    if (PARSE_DEBUG) std::cerr << "parse_line: invalid token found at start of line (LINE "
 505      << line_count << ")" << std::endl;
 506
 507    /* Invalid token found, return a parse error */
 508    return PROJECTM_PARSE_ERROR;
 509
 510
 511  case tEOL:  /* Empty line */
 512    line_mode = UNSET_LINE_MODE;
 513    return PROJECTM_SUCCESS;
 514
 515  case tEOF: /* End of File */
 516    line_mode = UNSET_LINE_MODE;
 517    line_count = 1;
 518    tokenWrapAroundEnabled = false;
 519    return EOF;
 520
 521  case tSemiColon: /* Indicates end of expression */
 522    tokenWrapAroundEnabled = false;
 523    return PROJECTM_SUCCESS;
 524
 525    /* Valid Case, either an initial condition or equation should follow */
 526  case tEq:
 527    lastLinePrefix = std::string(eqn_string);
 528    if (PARSE_DEBUG) std::cout << "last line prefix = \"" << eqn_string << "\"" << std::endl;
 529    // std::cerr << "parse_line: tEQ case, fs.peek()=\'" << fs.peek() << "\'" << std::endl;
 530    if (!fs)
 531      return PROJECTM_PARSE_ERROR;
 532    
 533//	char z = fs.get();
 534	char tmpChar;
 535	if ((tmpChar = fs.get()) == '\n') {
 536		tokenWrapAroundEnabled = false;
 537		return PROJECTM_PARSE_ERROR;	
 538	} else if (tmpChar == '\r') {
 539		tokenWrapAroundEnabled = false;
 540		return PROJECTM_PARSE_ERROR;
 541	} else
 542		fs.unget();
 543
 544 //   if (z == 2)
 545//	;
 546     // return PROJECTM_PARSE_ERROR;
 547    //else
 548     // fs.unget();
 549
 550
 551    /* CASE: PER FRAME INIT EQUATION */
 552    if (!strncmp(eqn_string, PER_FRAME_INIT_STRING, PER_FRAME_INIT_STRING_LENGTH))
 553    {
 554      tokenWrapAroundEnabled = true;
 555      //if (PARSE_DEBUG) printf("parse_line: per frame init equation found...(LINE %d)\n", line_count);
 556
 557      /* Parse the per frame equation */
 558      if ((init_cond = parse_per_frame_init_eqn(fs, preset, NULL)) == NULL)
 559      {
 560        //if (PARSE_DEBUG) printf("parse_line: per frame init equation parsing failed (LINE %d)\n", line_count);
 561        tokenWrapAroundEnabled = false;
 562        return PROJECTM_PARSE_ERROR;
 563      }
 564
 565      /* Insert the equation in the per frame equation tree */
 566      preset->per_frame_init_eqn_tree.insert(std::make_pair(init_cond->param->name, init_cond));
 567
 568      line_mode = PER_FRAME_INIT_LINE_MODE;
 569      return PROJECTM_SUCCESS;
 570    }
 571
 572    /* Per frame equation case */
 573    if (!strncmp(eqn_string, PER_FRAME_STRING, PER_FRAME_STRING_LENGTH))
 574    {
 575	tokenWrapAroundEnabled = true;
 576      /* Sometimes per frame equations are implicitly defined without the
 577      per_frame_ prefix. This informs the parser that one could follow */
 578      line_mode = PER_FRAME_LINE_MODE;
 579
 580      //if (PARSE_DEBUG) printf("parse_line: per frame equation found...(LINE %d)\n", line_count);
 581
 582      /* Parse the per frame equation */
 583      if ((per_frame_eqn = parse_per_frame_eqn(fs, ++per_frame_eqn_count, preset)) == NULL)
 584      {
 585        if (PARSE_DEBUG) printf("parse_line: per frame equation parsing failed (LINE %d)\n", line_count);
 586        tokenWrapAroundEnabled = false;
 587        return PROJECTM_PARSE_ERROR;
 588      }
 589
 590      /* Insert the equation in the per frame equation tree */
 591      preset->per_frame_eqn_tree.push_back(per_frame_eqn);
 592
 593      return PROJECTM_SUCCESS;
 594
 595    }
 596
 597    /* Wavecode initial condition case */
 598    if (!strncmp(eqn_string, WAVECODE_STRING, WAVECODE_STRING_LENGTH))
 599    {
 600      
 601      line_mode = CUSTOM_WAVE_WAVECODE_LINE_MODE;
 602
 603      return parse_wavecode(eqn_string, fs, preset);
 604    }
 605
 606    /* Custom Wave Prefix */
 607    if ((!strncmp(eqn_string, WAVE_STRING, WAVE_STRING_LENGTH)) &&
 608        ((eqn_string[5] >= 48) && (eqn_string[5] <= 57)))
 609    {
 610	tokenWrapAroundEnabled = true;
 611      //    if (PARSE_DEBUG) printf("parse_line wave prefix found: \"%s\"\n", eqn_string);
 612
 613      return parse_wave(eqn_string, fs, preset);
 614
 615    }
 616
 617
 618    /* Shapecode initial condition case */
 619    if (!strncmp(eqn_string, SHAPECODE_STRING, SHAPECODE_STRING_LENGTH))
 620    {
 621
 622      line_mode = CUSTOM_SHAPE_SHAPECODE_LINE_MODE;
 623
 624      if (PARSE_DEBUG) printf("parse_line: shapecode prefix found: \"%s\"\n", eqn_string);
 625
 626      return parse_shapecode(eqn_string, fs, preset);
 627    }
 628
 629    /* Custom Shape Prefix */
 630    if ((!strncmp(eqn_string, SHAPE_STRING, SHAPE_STRING_LENGTH)) &&
 631        ((eqn_string[6] >= 48) && (eqn_string[6] <= 57)))
 632    {
 633      tokenWrapAroundEnabled = true;
 634      if (PARSE_DEBUG) printf("parse_line shape prefix found: \"%s\"\n", eqn_string);
 635      return parse_shape(eqn_string, fs, preset);
 636
 637    }
 638
 639    /* Per pixel equation case */
 640    if (!strncmp(eqn_string, PER_PIXEL_STRING, PER_PIXEL_STRING_LENGTH))
 641    {
 642      tokenWrapAroundEnabled = true;
 643
 644      line_mode = PER_PIXEL_LINE_MODE;
 645
 646      if (parse_per_pixel_eqn(fs, preset, 0) < 0)
 647      {
 648        tokenWrapAroundEnabled = false;
 649        return PROJECTM_PARSE_ERROR;
 650      }
 651
 652
 653      if (PARSE_DEBUG) printf("parse_line: finished parsing per pixel equation (LINE %d)\n", line_count);
 654      return PROJECTM_SUCCESS;
 655    }
 656
 657    /* Sometimes equations are written implicitly in milkdrop files, in the form
 658
 659    per_frame_1 = p1 = eqn1; p2 = eqn2; p3 = eqn3;..; 
 660
 661    which is analagous to:
 662
 663    per_frame_1 = p1 = eqn1; per_frame_2 = p2 = eqn2; per_frame_3 = p3 = eqn3; ...;
 664
 665    The following line mode hack allows such implicit declaration of the 
 666    prefix that specifies the equation type. An alternative method
 667    may be to associate each equation line as list of equations separated
 668    by semicolons (and a new line ends the list). Instead, however, a global
 669    variable called "line_mode" specifies the last type of equation found,
 670    and bases any implicitly typed input on this fact
 671
 672    Note added by Carmelo Piccione (carmelo.piccione@gmail.com) 10/19/03
 673    */
 674
 675    /* Per frame line mode previously, try to parse the equation implicitly */
 676    if (line_mode == PER_FRAME_LINE_MODE)
 677    {
 678      tokenWrapAroundEnabled = true;
 679      if ((per_frame_eqn = parse_implicit_per_frame_eqn(fs, eqn_string, ++per_frame_eqn_count, preset)) == NULL)
 680      {
 681        tokenWrapAroundEnabled = false;
 682        return PROJECTM_PARSE_ERROR;
 683      }
 684
 685      /* Insert the equation in the per frame equation tree */
 686      preset->per_frame_eqn_tree.push_back(per_frame_eqn);
 687
 688
 689      return PROJECTM_SUCCESS;
 690
 691    }
 692    else if (line_mode == PER_FRAME_INIT_LINE_MODE)
 693    {
 694      tokenWrapAroundEnabled = true;
 695      if (PARSE_DEBUG) printf("parse_line: parsing implicit per frame init eqn)\n");
 696      if ((init_cond = parse_per_frame_init_eqn(fs, preset, NULL)) == NULL)
 697      {
 698        tokenWrapAroundEnabled = false;
 699        return PROJECTM_PARSE_ERROR;
 700      }
 701
 702      ++per_frame_init_eqn_count;
 703
 704      /* Insert the equation in the per frame equation tree */
 705      preset->per_frame_init_eqn_tree.insert(std::make_pair(init_cond->param->name, init_cond));
 706
 707      return PROJECTM_SUCCESS;
 708    }
 709    else if (line_mode == PER_PIXEL_LINE_MODE)
 710    {
 711      tokenWrapAroundEnabled = true;
 712      if (PARSE_DEBUG) printf("parse_line: implicit per pixel eqn (LINE %d)\n", line_count);
 713      return parse_per_pixel_eqn(fs, preset, eqn_string);
 714
 715
 716    }
 717    else if (line_mode == CUSTOM_WAVE_PER_POINT_LINE_MODE)
 718    {
 719      tokenWrapAroundEnabled = true;
 720      if (PARSE_DEBUG) printf("parse_line: implicit cwave ppoint eqn found (LINE %d)\n", line_count);
 721      //int len = strlen(eqn_string);
 722
 723      if (parse_wave_helper(fs, preset, last_custom_wave_id, last_eqn_type, eqn_string) < 0)
 724      {
 725        if (PARSE_DEBUG) printf("parse_line: failed to parse an implicit custom wave per point eqn\n");
 726        return PROJECTM_FAILURE;
 727      }
 728      return PROJECTM_SUCCESS;
 729    }
 730    else if (line_mode == CUSTOM_WAVE_PER_FRAME_LINE_MODE)
 731    {
 732      tokenWrapAroundEnabled = true;
 733      //Added by PJS. I hope I did it right
 734      CustomWave * custom_wave;
 735
 736      /* Retrieve custom shape associated with this id */
 737      if ((custom_wave = Preset::find_custom_object(last_custom_wave_id, preset->customWaves)) == NULL)
 738        return PROJECTM_FAILURE;
 739      return parse_wave_per_frame_eqn(fs, custom_wave, preset);
 740
 741    }
 742    else if (line_mode == CUSTOM_WAVE_WAVECODE_LINE_MODE)
 743    {
 744      if (PARSE_DEBUG) printf("unsupported line mode: CUSTOM_WAVE_WAVECODE_LINE_MODE\n");
 745      return PROJECTM_FAILURE;
 746    }
 747    else if (line_mode == CUSTOM_SHAPE_SHAPECODE_LINE_MODE)
 748    {
 749      if (PARSE_DEBUG) printf("unsupported line mode: CUSTOM_SHAPE_SHAPECODE_LINE_MODE\n");
 750      return PROJECTM_FAILURE;
 751    }
 752    else if (line_mode == CUSTOM_SHAPE_PER_FRAME_LINE_MODE)
 753    {
 754      tokenWrapAroundEnabled = true;
 755
 756      CustomShape * custom_shape;
 757
 758      /* Retrieve custom shape associated with this id */
 759      if ((custom_shape = Preset::find_custom_object(last_custom_shape_id, preset->customShapes)) == NULL)
 760        return PROJECTM_FAILURE;
 761
 762      return parse_shape_per_frame_eqn(fs, custom_shape, preset);
 763
 764    }
 765    else if (line_mode == CUSTOM_SHAPE_PER_FRAME_INIT_LINE_MODE)
 766    {
 767      tokenWrapAroundEnabled = true;
 768      CustomShape * custom_shape;
 769
 770      /* Retrieve custom shape associated with this id */
 771      if ((custom_shape = preset->find_custom_object(last_custom_shape_id, preset->customShapes)) == NULL)
 772        return PROJECTM_FAILURE;
 773
 774      return parse_shape_per_frame_init_eqn(fs, custom_shape, preset);
 775
 776    }
 777
 778    if (PARSE_DEBUG) printf("parse_line: found initial condition: name = \"%s\" (LINE %d)\n", eqn_string, line_count);
 779    /* Evaluate the initial condition */
 780    if ((init_cond = parse_init_cond(fs, eqn_string, preset)) == NULL)
 781    {
 782      if (PARSE_DEBUG) printf("parse_line: failed to parse initial condition (LINE %d)\n", line_count);
 783      return PROJECTM_PARSE_ERROR;
 784    }
 785
 786    /* Add equation to initial condition tree */
 787    preset->init_cond_tree.insert(std::make_pair(init_cond->param->name, init_cond));
 788
 789    /* Finished with initial condition line */
 790    //    if (PARSE_DEBUG) printf("parse_line: initial condition parsed successfully\n");
 791
 792    return PROJECTM_SUCCESS;
 793
 794    /* END INITIAL CONDITIONING PARSING */
 795
 796  default: /* an uncaught type or an error has occurred */
 797    if (PARSE_DEBUG) printf("parse_line: uncaught case, token val = %d\n", token);
 798    return PROJECTM_PARSE_ERROR;
 799  }
 800
 801  /* Because of the default in the case statement,
 802     control flow should never actually reach here */
 803  return PROJECTM_PARSE_ERROR;
 804}
 805
 806
 807
 808/* Parses a general expression, this function is the meat of the parser */
 809GenExpr * Parser::parse_gen_expr ( std::istream &  fs, TreeExpr * tree_expr, Preset * preset)
 810{
 811
 812  int i;
 813  char string[MAX_TOKEN_SIZE];
 814  token_type token;
 815  GenExpr * gen_expr;
 816  float val;
 817  Param * param = NULL;
 818  Func * func;
 819  GenExpr ** expr_list;
 820
 821  switch (token = parseToken(fs,string))
 822  {
 823    /* Left Parentice Case */
 824  case tLPr:
 825    //std::cerr << "token before tLPr:" << string << std::endl;
 826    /* CASE 1 (Left Parentice): See if the previous string before this parentice is a function name */
 827    if ((func = BuiltinFuncs::find_func(string)) != NULL)
 828    {
 829      if (PARSE_DEBUG)
 830      {
 831        std::cerr << "parse_gen_expr: found prefix function (name = \""
 832        << func->getName() << "\") (LINE " << line_count << ")" << std::endl;
 833      }
 834
 835      /* Parse the functions arguments */
 836      if ((expr_list = parse_prefix_args(fs, func->getNumArgs(), preset)) == NULL)
 837      {
 838        if (PARSE_DEBUG)
 839        {
 840          std::cerr << "parse_prefix_args: failed to generate an expresion list! (LINE "
 841          << line_count << ")" << std::endl;
 842        }
 843        if ( tree_expr != NULL )
 844        {
 845          delete tree_expr;
 846        }
 847        return NULL;
 848      }
 849
 850      /* Convert function to expression */
 851      if ((gen_expr = GenExpr::prefun_to_expr((float (*)(void *))func->func_ptr, expr_list, func->getNumArgs())) == NULL)
 852      {
 853        if (PARSE_DEBUG) printf("parse_prefix_args: failed to convert prefix function to general expression (LINE %d) \n",
 854                                  line_count);
 855        if (tree_expr)
 856          delete tree_expr;
 857        for (i = 0; i < func->getNumArgs();i++)
 858          delete expr_list[i];
 859        free(expr_list);
 860        expr_list = NULL;
 861        return NULL;
 862      }
 863
 864      token = parseToken(fs, string);
 865
 866      if (*string != 0)
 867      {
 868        if (PARSE_DEBUG) printf("parse_prefix_args: empty string expected, but not found...(LINE %d)\n", line_count);
 869        /* continue anyway for now, could be implicit multiplication */
 870      }
 871
 872      return parse_infix_op(fs, token, insert_gen_expr(gen_expr, &tree_expr), preset);
 873    }
 874
 875
 876    /* Case 2: (Left Parentice), a string coupled with a left parentice. Either an error or implicit
 877       multiplication operator. For now treat it as an error */
 878    if (*string != 0)
 879    {
 880      std::cerr << "token prefix is " << *string << std::endl;
 881      if (PARSE_DEBUG) printf("parse_gen_expr: implicit multiplication case unimplemented!\n");
 882      if (tree_expr)
 883        delete tree_expr;
 884      return NULL;
 885    }
 886
 887    /* CASE 3 (Left Parentice): the following is enclosed parentices to change order
 888       of operations. So we create a new expression tree */
 889
 890    if ((gen_expr = parse_gen_expr(fs, NULL, preset)) == NULL)
 891    {
 892      if (PARSE_DEBUG) printf("parse_gen_expr:  found left parentice, but failed to create new expression tree \n");
 893      if (tree_expr)
 894      delete tree_expr;
 895      return NULL;
 896    }
 897
 898    if (PARSE_DEBUG) printf("parse_gen_expr: finished enclosed expression tree...\n");
 899    token = parseToken(fs, string);
 900    return parse_infix_op(fs, token, insert_gen_expr(gen_expr, &tree_expr), preset);
 901
 902    /* Plus is a prefix operator check */
 903  case tPlus:
 904    if (*string == 0)
 905    {
 906
 907      if (PARSE_DEBUG) printf("parse_gen_expr: plus used as prefix (LINE %d)\n", line_count);
 908
 909      /* Treat prefix plus as implict 0 preceding operator */
 910      gen_expr = GenExpr::const_to_expr(0);
 911
 912      return parse_infix_op(fs, tPositive, insert_gen_expr(gen_expr, &tree_expr), preset);
 913    }
 914
 915    /* Minus is a prefix operator check */
 916  case tMinus:
 917    if (*string == 0)
 918    {
 919
 920      /* Use the negative infix operator, but first add an implicit zero to the operator tree */
 921      gen_expr = GenExpr::const_to_expr(0);
 922      //return parse_gen_expr(fs, insert_gen_expr(gen_expr, &tree_expr), preset);
 923      return parse_infix_op(fs, tNegative, insert_gen_expr(gen_expr, &tree_expr), preset);
 924    }
 925
 926    /* All the following cases are strings followed by an infix operator or terminal */
 927  case tRPr:
 928  case tEOL:
 929  case tEOF:
 930  case tSemiColon:
 931  case tComma:
 932
 933    /* CASE 1 (terminal): string is empty, but not null. Not sure if this will actually happen
 934       any more. */
 935    if (*string == 0)
 936    {
 937      if (PARSE_DEBUG) printf("parse_gen_expr: empty string coupled with terminal (LINE %d) \n", line_count);
 938      return parse_infix_op(fs, token, tree_expr, preset);
 939
 940    }
 941
 942  default:
 943
 944    /* CASE 0: Empty string, parse error */
 945    if (*string == 0)
 946    {
 947      if (tree_expr)
 948        delete tree_expr;
 949      return NULL;
 950    }
 951
 952    /* CASE 1: Check if string is a just a floating point number */
 953    if (string_to_float(string, &val) != PROJECTM_PARSE_ERROR)
 954    {
 955      if ((gen_expr = GenExpr::const_to_expr(val)) == NULL)
 956      {
 957        if (tree_expr)
 958          delete tree_expr;
 959        return NULL;
 960      }
 961
 962      /* Parse the rest of the line */
 963      return parse_infix_op(fs, token, insert_gen_expr(gen_expr, &tree_expr), preset);
 964
 965    }
 966
 967
 968    /* CASE 4: custom shape variable */
 969    if (current_shape != NULL)
 970    {
 971      if ((param = ParamUtils::find<ParamUtils::NO_CREATE>(std::string(string), &current_shape->param_tree)) == NULL)
 972      {
 973        if ((param = preset->builtinParams.find_builtin_param(std::string(string))) == NULL)
 974          if ((param = ParamUtils::find<ParamUtils::AUTO_CREATE>(std::string(string), &current_shape->param_tree)) == NULL)
 975          {
 976            if (tree_expr)
 977              delete tree_expr;
 978            return NULL;
 979          }
 980      }
 981
 982      if (PARSE_DEBUG)
 983      {
 984        std::cerr << "parse_gen_expr: custom shape parameter (name = "
 985        << param->name << ")" << std::endl;
 986      }
 987
 988
 989      /* Convert parameter to an expression */
 990      if ((gen_expr = GenExpr::param_to_expr(param)) == NULL)
 991      {
 992        delete tree_expr;
 993        return NULL;
 994      }
 995
 996      //if (PARSE_DEBUG) printf("converted to expression (LINE %d)\n", line_count);
 997
 998      /* Parse the rest of the line */
 999      return parse_infix_op(fs, token, insert_gen_expr(gen_expr, &tree_expr), preset);
1000    }
1001
1002    /* CASE 5: custom wave variable */
1003    if (current_wave != NULL)
1004    {
1005      if ((param = ParamUtils::find<ParamUtils::NO_CREATE>(std::string(string), &current_wave->param_tree)) == NULL)
1006      {
1007        if ((param = preset->builtinParams.find_builtin_param(std::string(string))) == NULL)
1008          if ((param = ParamUtils::find<ParamUtils::AUTO_CREATE>(std::string(string), &current_wave->param_tree)) == NULL)
1009          {
1010            if (tree_expr)
1011              delete tree_expr;
1012            return NULL;
1013          }
1014      }
1015      assert(param);
1016
1017      if (PARSE_DEBUG)
1018      {
1019        std::cerr << "parse_gen_expr: custom wave parameter (name = " <<  param->name << ")" << std::endl;
1020
1021      }
1022
1023      /* Convert parameter to an expression */
1024      if ((gen_expr = GenExpr::param_to_expr(param)) == NULL)
1025      {
1026        delete tree_expr;
1027        return NULL;
1028      }
1029
1030      //if (PARSE_DEBUG) printf("converted to expression (LINE %d)\n", line_count);
1031
1032      /* Parse the rest of the line */
1033      return parse_infix_op(fs, token, insert_gen_expr(gen_expr, &tree_expr), preset);
1034
1035    }
1036
1037    /* CASE 6: regular parameter. Will be created if necessary and the string has no invalid characters */
1038    if ((param = ParamUtils::find(string, &preset->builtinParams, &preset->user_param_tree)) != NULL)
1039    {
1040
1041      if (PARSE_DEBUG)
1042      {
1043        std::cerr << "parse_gen_expr: parameter (name = \"" << param->name << "\")..." << std::endl;
1044      }
1045
1046      /* Convert parameter to an expression */
1047      if ((gen_expr = GenExpr::param_to_expr(param)) == NULL)
1048      {
1049        delete tree_expr;
1050        return NULL;
1051      }
1052
1053      //if (PARSE_DEBUG) printf("converted to expression (LINE %d)\n", line_count);
1054
1055      /* Parse the rest of the line */
1056      return parse_infix_op(fs, token, insert_gen_expr(gen_expr, &tree_expr), preset);
1057
1058    }
1059
1060    /* CASE 7: Bad string, give up */
1061    if (PARSE_DEBUG)
1062    {
1063      printf( "parse_gen_expr: syntax error [string = \"%s\"] (LINE %d)\n", string, line_count);
1064
1065    }
1066    if (tree_expr)
1067      delete tree_expr;
1068    return NULL;
1069  }
1070}
1071
1072
1073
1074/* Inserts expressions into tree according to operator precedence.
1075   If root is null, a new tree is created, with infix_op as only element */
1076
1077TreeExpr * Parser::insert_infix_op(InfixOp * infix_op, TreeExpr **root)
1078{
1079
1080  TreeExpr * new_root;
1081
1082  /* Sanity check */
1083  if (infix_op == NULL)
1084    return NULL;
1085
1086  /* The root is null, so make this operator
1087     the new root */
1088
1089  if (*root == NULL)
1090  {
1091    new_root = new TreeExpr(infix_op, NULL, NULL, NULL);
1092    *root = new_root;
1093    return new_root;
1094  }
1095
1096  /* The root node is not an infix function,
1097     so we make this infix operator the new root  */
1098
1099  if ((*root)->infix_op == NULL)
1100  {
1101    new_root = new TreeExpr(infix_op, NULL, *root, NULL);
1102    (*root) = new_root;
1103    return new_root;
1104  }
1105
1106  /* The root is an infix function. If the precedence
1107     of the item to be inserted is greater than the root's
1108     precedence, then make gen_expr the root */
1109
1110  if (infix_op->precedence > (*root)->infix_op->precedence)
1111  {
1112    new_root = new TreeExpr(infix_op, NULL, *root, NULL);
1113    (*root) = new_root;
1114    return new_root;
1115  }
1116
1117  /* If control flow reaches here, use a recursive helper
1118     with the knowledge that the root is higher precedence
1119     than the item to be inserted */
1120
1121  insert_infix_rec(infix_op, *root);
1122  return *root;
1123
1124}
1125
1126
1127TreeExpr * Parser::insert_gen_expr(GenExpr * gen_expr, TreeExpr ** root)
1128{
1129
1130  TreeExpr * new_root;
1131
1132  /* If someone foolishly passes a null
1133     pointer to insert, return the original tree */
1134
1135  if (gen_expr == NULL)
1136  {
1137    return *root;
1138  }
1139
1140  /* If the root is null, generate a new expression tree,
1141     using the passed expression as the root element */
1142
1143  if (*root == NULL)
1144  {
1145    new_root = new TreeExpr(NULL, gen_expr, NULL, NULL);
1146    *root = new_root;
1147    return new_root;
1148  }
1149
1150
1151  /* Otherwise. the new element definitely will not replace the current root.
1152     Use a recursive helper function to do insertion */
1153
1154  insert_gen_rec(gen_expr, *root);
1155  return *root;
1156}
1157
1158/* A recursive helper function to insert general expression elements into the operator tree */
1159int Parser::insert_gen_rec(GenExpr * gen_expr, TreeExpr * root)
1160{
1161
1162  /* Trivial Case: root is null */
1163
1164  if (root == NULL)
1165  {
1166    //if (PARSE_DEBUG) printf("insert_gen_rec: root is null, returning failure\n");
1167    return PROJECTM_FAILURE;
1168  }
1169
1170
1171  /* The current node's left pointer is null, and this
1172     current node is an infix operator, so insert the
1173     general expression at the left pointer */
1174
1175  if ((root->left == NULL) && (root->infix_op != NULL))
1176  {
1177    root->left = new TreeExpr(NULL, gen_expr, NULL, NULL);
1178    return PROJECTM_SUCCESS;
1179  }
1180
1181  /* The current node's right pointer is null, and this
1182     current node is an infix operator, so insert the
1183     general expression at the right pointer */
1184
1185  if ((root->right == NULL) && (root->infix_op != NULL))
1186  {
1187    root->right = new TreeExpr(NULL, gen_expr, NULL, NULL);
1188    return PROJECTM_SUCCESS;
1189  }
1190
1191  /* Otherwise recurse down to the left. If
1192     this succeeds then return. If it fails, try
1193     recursing down to the right */
1194
1195  if (insert_gen_rec(gen_expr, root->left) == PROJECTM_FAILURE)
1196    return insert_gen_rec(gen_expr, root->right);
1197
1198  /* Impossible for control flow to reach here, but in
1199     the world of C programming, who knows... */
1200  if (PARSE_DEBUG) printf("insert_gen_rec: should never reach here!\n");
1201  return PROJECTM_FAILURE;
1202}
1203
1204
1205/* A recursive helper function to insert infix arguments by operator precedence */
1206int Parser::insert_infix_rec(InfixOp * infix_op, TreeExpr * root)
1207{
1208
1209  /* Shouldn't happen, implies a parse error */
1210
1211  if (root == NULL)
1212    return PROJECTM_FAILURE;
1213
1214  /* Also shouldn't happen, also implies a (different) parse error */
1215
1216  if (root->infix_op == NULL)
1217    return PROJECTM_FAILURE;
1218
1219  /* Left tree is empty, attach this operator to it.
1220     I don't think this will ever happen */
1221  if (root->left == NULL)
1222  {
1223    root->left = new TreeExpr(infix_op, NULL, root->left, NULL);
1224    return PROJECTM_SUCCESS;
1225  }
1226
1227  /* Right tree is empty, attach this operator to it */
1228  if (root->right == NULL)
1229  {
1230    root->right = new TreeExpr(infix_op, NULL, root->right, NULL);
1231    return PROJECTM_SUCCESS;
1232  }
1233
1234  /* The left element can now be ignored, since there is no way for this
1235     operator to use those expressions */
1236
1237  /* If the right element is not an infix operator,
1238     then insert the expression here, attaching the old right branch
1239     to the left of the new expression */
1240
1241  if (root->right->infix_op == NULL)
1242  {
1243    root->right = new TreeExpr(infix_op, NULL, root->right, NULL);
1244    return PROJECTM_SUCCESS;
1245  }
1246
1247  /* Traverse deeper if the inserting operator precedence is less than the
1248     the root's right operator precedence */
1249  if (infix_op->precedence < root->right->infix_op->precedence)
1250    return insert_infix_rec(infix_op, root->right);
1251
1252  /* Otherwise, insert the operator here */
1253
1254  root->right = new TreeExpr(infix_op, NULL, root->right, NULL);
1255  return PROJECTM_SUCCESS;
1256
1257}
1258
1259/* Parses an infix operator */
1260GenExpr * Parser::parse_infix_op(std::istream &  fs, token_type token, TreeExpr * tree_expr, Preset * preset)
1261{
1262
1263  GenExpr * gen_expr;
1264
1265  switch (token)
1266  {
1267    /* All the infix operators */
1268  case tPlus:
1269    if (PARSE_DEBUG) printf("parse_infix_op: found addition operator (LINE %d)\n", line_count);
1270    if (PARSE_DEBUG) std::cerr << "WRAP AROUND IS " <<  tokenWrapAroundEnabled << std::endl;
1271
1272    return parse_gen_expr(fs, insert_infix_op(Eval::infix_add, &tree_expr), preset);
1273  case tMinus:
1274    if (PARSE_DEBUG) printf("parse_infix_op: found subtraction operator (LINE %d)\n", line_count);
1275    return parse_gen_expr(fs, insert_infix_op(Eval::infix_minus, &tree_expr), preset);
1276  case tMult:
1277    if (PARSE_DEBUG) printf("parse_infix_op: found multiplication operator (LINE %d)\n", line_count);
1278    return parse_gen_expr(fs, insert_infix_op(Eval::infix_mult, &tree_expr), preset);
1279  case tDiv:
1280    if (PARSE_DEBUG) printf("parse_infix_op: found division operator (LINE %d)\n", line_count);
1281    return parse_gen_expr(fs, insert_infix_op(Eval::infix_div, &tree_expr), preset);
1282  case tMod:
1283    if (PARSE_DEBUG) printf("parse_infix_op: found modulo operator (LINE %d)\n", line_count);
1284    return parse_gen_expr(fs, insert_infix_op(Eval::infix_mod, &tree_expr), preset);
1285  case tOr:
1286    if (PARSE_DEBUG) printf("parse_infix_op: found bitwise or operator (LINE %d)\n", line_count);
1287    return parse_gen_expr(fs, insert_infix_op(Eval::infix_or, &tree_expr), preset);
1288  case tAnd:
1289    if (PARSE_DEBUG) printf("parse_infix_op: found bitwise and operator (LINE %d)\n", line_count);
1290    return parse_gen_expr(fs, insert_infix_op(Eval::infix_and, &tree_expr), preset);
1291  case tPositive:
1292    if (PARSE_DEBUG) printf("parse_infix_op: found positive operator (LINE %d)\n", line_count);
1293    return parse_gen_expr(fs, insert_infix_op(Eval::infix_positive, &tree_expr), preset);
1294  case tNegative:
1295    if (PARSE_DEBUG) printf("parse_infix_op: found negative operator (LINE %d)\n", line_count);
1296    return parse_gen_expr(fs, insert_infix_op(Eval::infix_negative, &tree_expr), preset);
1297
1298  case tEOL:
1299  case tEOF:
1300  case tSemiColon:
1301  case tRPr:
1302  case tComma:
1303    if (PARSE_DEBUG) printf("parse_infix_op: terminal found (LINE %d)\n", line_count);
1304    gen_expr = new GenExpr(TREE_T, (void*)tree_expr);
1305    assert(gen_expr);
1306    return gen_expr;
1307  default:
1308    if (PARSE_DEBUG) printf("parse_infix_op: operator or terminal expected, but not found (LINE %d)\n", line_count);
1309    delete tree_expr;
1310    return NULL;
1311  }
1312
1313  /* Will never happen */
1314  return NULL;
1315
1316}
1317
1318/* Parses an integer, checks for +/- prefix */
1319int Parser::parse_int(std::istream &  fs, int * int_ptr)
1320{
1321
1322  char string[MAX_TOKEN_SIZE];
1323  token_type token;
1324  int sign;
1325  char * end_ptr = (char*)" ";
1326
1327  token = parseToken(fs, string);
1328
1329
1330  switch (token)
1331  {
1332  case tMinus:
1333    sign = -1;
1334    token = parseToken(fs, string);
1335    break;
1336  case tPlus:
1337    sign = 1;
1338    token = parseToken(fs, string);
1339    break;
1340  default:
1341    sign = 1;
1342    break;
1343  }
1344
1345
1346  if (string[0] == 0)
1347    return PROJECTM_PARSE_ERROR;
1348
1349  /* Convert the string to an integer. *end_ptr
1350     should end up pointing to null terminator of 'string' 
1351     if the conversion was successful. */
1352  //  printf("STRING: \"%s\"\n", string);
1353
1354  (*int_ptr) = sign*strtol(string, &end_ptr, 10);
1355
1356  /* If end pointer is a return character or null terminator, all is well */
1357  if ((*end_ptr == '\r') || (*end_ptr == '\0'))
1358    return PROJECTM_SUCCESS;
1359
1360  return PROJECTM_PARSE_ERROR;
1361
1362}
1363/* Parses a floating point number */
1364int Parser::string_to_float(char * string, float * float_ptr)
1365{
1366  bool conv_success;
1367
1368  if (*string == 0)
1369    return PROJECTM_PARSE_ERROR;
1370
1371  (*float_ptr) = fastatof(string, conv_success);
1372
1373  if (conv_success)
1374    return PROJECTM_SUCCESS;
1375  else
1376    return PROJECTM_PARSE_ERROR;
1377}
1378
1379/* Parses a floating point number */
1380int Parser::parse_float(std::istream &  fs, float * float_ptr)
1381{
1382
1383  char string[MAX_TOKEN_SIZE];
1384  bool conv_success;
1385  token_type token;
1386  int sign;
1387
1388  token = parseToken(fs, string);
1389
1390  switch (token)
1391  {
1392  case tMinus:
1393    sign = -1;
1394    token = parseToken(fs, string);
1395    break;
1396  case tPlus:
1397    sign = 1;
1398    token = parseToken(fs, string);
1399    break;
1400  default:
1401    sign = 1;
1402  }
1403
1404  if (string[0] == 0)
1405    return PROJECTM_PARSE_ERROR;
1406
1407  (*float_ptr) = sign*fastatof(string, conv_success);
1408
1409  if (conv_success)
1410    return PROJECTM_SUCCESS;
1411  else
1412    return PROJECTM_PARSE_ERROR;
1413}
1414
1415/* Parses a per frame equation. That is, interprets a stream of data as a per frame equation */
1416PerFrameEqn * Parser::parse_per_frame_eqn(std::istream &  fs, int index, Preset * preset)
1417{
1418
1419  char string[MAX_TOKEN_SIZE];
1420  Param * param;
1421  PerFrameEqn * per_frame_eqn;
1422  GenExpr * gen_expr;
1423
1424
1425  if (parseToken(fs, string) != tEq)
1426  {
1427    if (PARSE_DEBUG) printf("parse_per_frame_eqn: no equal sign after string \"%s\" (LINE %d)\n", string, line_count);
1428    return NULL;
1429  }
1430
1431  /* Find the parameter associated with the string, create one if necessary */
1432  if ((param = ParamUtils::find(string, &preset->builtinParams, &preset->user_param_tree)) == NULL)
1433  {
1434    return NULL;
1435  }
1436  if (PARSE_DEBUG) std::cerr << "parse_per_frame_eqn: parameter \"" << param->name << "\" retrieved (LINE" << line_count << ")" << std::endl;
1437  /* Make sure parameter is writable */
1438  if (param->flags & P_FLAG_READONLY)
1439  {
1440    if (PARSE_DEBUG) std::cerr << "parse_per_frame_eqn: parameter \"" << param->name << "\" %s is marked as read only (LINE " << line_count << ")" << std::endl;
1441    return NULL;
1442  }
1443
1444  /* Parse right side of equation as an expression */
1445  if ((gen_expr = parse_gen_expr(fs, NULL, preset)) == NULL)
1446  {
1447    if (PARSE_DEBUG) printf("parse_per_frame_eqn: equation evaluated to null (LINE %d)\n", line_count);
1448    return NULL;
1449  }
1450
1451  if (PARSE_DEBUG) printf("parse_per_frame_eqn: finished per frame equation evaluation (LINE %d)\n", line_count);
1452
1453  /* Create a new per frame equation */
1454  if ((per_frame_eqn = new PerFrameEqn(index, param, gen_expr)) == NULL)
1455  {
1456    if (PARSE_DEBUG) printf("parse_per_frame_eqn: failed to create a new per frame eqn, out of memory?\n");
1457    delete gen_expr;
1458    return NULL;
1459  }
1460
1461  if (PARSE_DEBUG) printf("parse_per_frame_eqn: per_frame eqn parsed succesfully\n");
1462
1463  return per_frame_eqn;
1464}
1465
1466/* Parses an 'implicit' per frame equation. That is, interprets a stream of data as a per frame equation without a prefix */
1467PerFrameEqn * Parser::parse_implicit_per_frame_eqn(std::istream &  fs, char * param_string, int index, Preset * preset)
1468{
1469
1470  Param * param;
1471  PerFrameEqn * per_frame_eqn;
1472  GenExpr * gen_expr;
1473
1474  if (fs == NULL)
1475    return NULL;
1476  if (param_string == NULL)
1477    return NULL;
1478  if (preset == NULL)
1479    return NULL;
1480
1481  //rintf("param string: %s\n", param_string);
1482  /* Find the parameter associated with the string, create one if necessary */
1483  if ((param = ParamUtils::find(param_string, &preset->builtinParams, &preset->user_param_tree)) == NULL)
1484  {
1485    return NULL;
1486  }
1487
1488  //printf("parse_implicit_per_frame_eqn: param is %s\n", param->name);
1489
1490  /* Make sure parameter is writable */
1491  if (param->flags & P_FLAG_READONLY)
1492  {
1493    if (PARSE_DEBUG) printf("parse_implicit_per_frame_eqn: parameter %s is marked as read only (LINE %d)\n", param->name.c_str(), line_count);
1494    return NULL;
1495  }
1496
1497  /* Parse right side of equation as an expression */
1498  if ((gen_expr = parse_gen_expr(fs, NULL, preset)) == NULL)
1499  {
1500    if (PARSE_DEBUG) printf("parse_implicit_per_frame_eqn: equation evaluated to null (LINE %d)\n", line_count);
1501    return NULL;
1502  }
1503
1504  if (PARSE_DEBUG) printf("parse_implicit_per_frame_eqn: finished per frame equation evaluation (LINE %d)\n", line_count);
1505
1506  /* Create a new per frame equation */
1507  if ((per_frame_eqn = new PerFrameEqn(index, param, gen_expr)) == NULL)
1508  {
1509    if (PARSE_DEBUG) printf("parse_implicit_per_frame_eqn: failed to create a new per frame eqn, out of memory?\n");
1510    delete gen_expr;
1511    return NULL;
1512  }
1513
1514  if (PARSE_DEBUG) printf("parse_implicit_per_frame_eqn: per_frame eqn parsed succesfully\n");
1515
1516  return per_frame_eqn;
1517}
1518
1519/* Parses an initial condition */
1520InitCond * Parser::parse_init_cond(std::istream &  fs, char * name, Preset * preset)
1521{
1522
1523  Param * param;
1524  CValue init_val;
1525  InitCond * init_cond;
1526
1527  if (name == NULL)
1528    return NULL;
1529  if (preset == NULL)
1530    return NULL;
1531
1532  /* Search for the paramater in the database, creating it if necessary */
1533  if ((param = ParamUtils::find(name, &preset->builtinParams, &preset->user_param_tree)) == NULL)
1534  {
1535    return NULL;
1536  }
1537
1538  if (PARSE_DEBUG) printf("parse_init_cond: parameter = \"%s\" (LINE %d)\n", param->name.c_str(), line_count);
1539
1540  if (param->flags & P_FLAG_READONLY)
1541  {
1542    if (PARSE_DEBUG) printf("parse_init_cond: builtin parameter \"%s\" marked as read only!\n", param->name.c_str());
1543    return NULL;
1544  }
1545
1546  /* At this point, a parameter has been created or was found
1547     in the database. */
1548
1549  if (PARSE_DEBUG) printf("parse_init_cond: parsing initial condition value... (LINE %d)\n", line_count);
1550
1551  /* integer value (boolean is an integer in C) */
1552  if ( (param->type == P_TYPE_BOOL))
1553  {
1554    int bool_test;
1555    if ((parse_int(fs, &bool_test)) == PROJECTM_PARSE_ERROR)
1556    {
1557      if (PARSE_DEBUG) printf("parse_init_cond: error parsing integer!\n");
1558      return NULL;
1559    }
1560    init_val.bool_val = bool_test;
1561  }
1562
1563  else if ((param->type == P_TYPE_INT))
1564  {
1565    if ((parse_int(fs, (int*)&init_val.int_val)) == PROJECTM_PARSE_ERROR)
1566    {
1567      if (PARSE_DEBUG) printf("parse_init_cond: error parsing integer!\n");
1568      return NULL;
1569    }
1570  }
1571
1572  /* float value */
1573  else if (param->type == P_TYPE_DOUBLE)
1574  {
1575    if ((parse_float(fs, (float*)&init_val.float_val)) == PROJECTM_PARSE_ERROR)
1576    {
1577      if (PARSE_DEBUG) printf("parse_init_cond: error parsing float!\n");
1578      return NULL;
1579    }
1580  }
1581
1582  /* Unknown value */
1583  else
1584  {
1585    if (PARSE_DEBUG) printf("parse_init_cond: unknown parameter type!\n");
1586    return NULL;
1587  }
1588
1589  /* Create new initial condition */
1590  if ((init_cond = new InitCond(param, init_val)) == NULL)
1591  {
1592    if (PARSE_DEBUG) printf("parse_init_cond: new_init_cond failed!\n");
1593    return NULL;
1594  }
1595
1596  /* Finished */
1597  return init_cond;
1598}
1599
1600/* Parses a per frame init equation, not sure if this works right now */
1601InitCond * Parser::parse_per_frame_init_eqn(std::istream &  fs, Preset * preset, std::map<std::string,Param*> * database)
1602{
1603
1604  char name[MAX_TOKEN_SIZE];
1605  Param * param = NULL;
1606  CValue init_val;
1607  InitCond * init_cond;
1608  GenExpr * gen_expr;
1609  float val;
1610  token_type token;
1611
1612
1613  if (preset == NULL)
1614    return NULL;
1615  if (fs == NULL)
1616    return NULL;
1617
1618  if ((token = parseToken(fs, name)) != tEq)
1619    return NULL;
1620
1621
1622  /* If a database was specified,then use ParamUtils::find_db instead */
1623  if ((database != NULL) && ((param = ParamUtils::find<ParamUtils::AUTO_CREATE>(name, database)) == NULL))
1624  {
1625    return NULL;
1626  }
1627
1628  /* Otherwise use the builtin parameter and user databases. This is confusing. Sorry. */
1629  if ((param == NULL) && ((param = ParamUtils::find(name, &preset->builtinParams, &preset->user_param_tree)) == NULL))
1630  {
1631    return NULL;
1632  }
1633
1634  if (PARSE_DEBUG) printf("parse_per_frame_init_eqn: parameter = \"%s\" (LINE %d)\n", param->name.c_str(), line_count);
1635
1636  if (param->flags & P_FLAG_READONLY)
1637  {
1638    if (PARSE_DEBUG) printf("pars_per_frame_init_eqn: builtin parameter \"%s\" marked as read only!\n", param->name.c_str());
1639    return NULL;
1640  }
1641
1642  /* At this point, a parameter has been created or was found
1643     in the database. */
1644
1645  if (PARSE_DEBUG) printf("parse_per_frame_init_eqn: parsing right hand side of per frame init equation.. (LINE %d)\n", line_count);
1646
1647  if ((gen_expr = parse_gen_expr(fs, NULL, preset)) == NULL)
1648  {
1649    if (PARSE_DEBUG) printf("parse_per_frame_init_eqn: failed to parse general expresion!\n");
1650    return NULL;
1651  }
1652
1653  /* Compute initial condition value */
1654  val = gen_expr->eval_gen_expr(-1,-1);
1655
1656  /* Free the general expression now that we are done with it */
1657  delete gen_expr;
1658
1659  /* integer value (boolean is an integer in C) */
1660  if (param->type == P_TYPE_BOOL)
1661  {
1662    init_val.bool_val = (bool)val;
1663  }
1664
1665  else if ((param->type == P_TYPE_INT))
1666  {
1667    init_val.int_val = (int)val;
1668  }
1669
1670  /* float value */
1671  else if (param->type == P_TYPE_DOUBLE)
1672  {
1673    init_val.float_val = val;
1674  }
1675
1676  /* Unknown value */
1677  else
1678  {
1679    if (PARSE_DEBUG) printf("pase_per_frame_init_eqn: unknown parameter type!\n");
1680    return NULL;
1681  }
1682
1683
1684  /* Create new initial condition */
1685  if ((init_cond = new InitCond(param, init_val)) == NULL)
1686  {
1687    if (PARSE_DEBUG) printf("parse_per_frame_init_eqn: new_init_cond failed!\n");
1688    return NULL;
1689  }
1690
1691  init_cond->evaluate(true);
1692
1693  /* Finished */
1694  return init_cond;
1695}
1696
1697int Parser::parse_wavecode(char * token, std::istream &  fs, Preset * preset)
1698{
1699
1700  char * var_string;
1701  InitCond * init_cond;
1702  CustomWave * custom_wave;
1703  int id;
1704  CValue init_val;
1705  Param * param;
1706
1707  assert(preset);
1708  assert(fs);
1709  assert(token);
1710
1711  /* token should be in the form wavecode_N_var, such as wavecode_1_samples */
1712
1713  /* Get id and variable name from token string */
1714  if (parse_wavecode_prefix(token, &id, &var_string) < 0)
1715    return PROJECTM_PARSE_ERROR;
1716
1717  last_custom_wave_id = id;
1718
1719  if (PARSE_DEBUG) printf("parse_wavecode: wavecode id = %d, parameter = \"%s\"\n", id, var_string);
1720
1721  /* Retrieve custom wave information from preset, allocating new one if necessary */
1722  if ((custom_wave = Preset::find_custom_object(id, preset->customWaves)) == NULL)
1723  {
1724    std::cerr << "parse_wavecode: failed to load (or create) custom wave (id = "
1725    << id << ")!\n" << std::endl;
1726
1727    return PROJECTM_FAILURE;
1728  }
1729
1730  if (PARSE_DEBUG) printf("parse_wavecode: custom wave found (id = %d)\n", custom_wave->id);
1731
1732  /* Retrieve parameter from this custom waves parameter db */
1733  if ((param = ParamUtils::find<ParamUtils::AUTO_CREATE>(var_string,&custom_wave->param_tree)) == NULL)
1734    return PROJECTM_FAILURE;
1735
1736  if (PARSE_DEBUG) printf("parse_wavecode: custom wave parameter found (name = %s)\n", param->name.c_str());
1737
1738  /* integer value (boolean is an integer in C) */
1739
1740  if ((param->type == P_TYPE_BOOL))
1741  {
1742    int bool_test;
1743    if ((parse_int(fs, &bool_test)) == PROJECTM_PARSE_ERROR)
1744    {
1745
1746      if (PARSE_DEBUG) printf("parse_wav…

Large files files are truncated, but you can click here to view the full file