⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nvvertparse.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * Mesa 3-D graphics library
 * Version:  6.3
 *
 * Copyright (C) 1999-2004  Brian Paul   All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * \file nvvertparse.c
 * NVIDIA vertex program parser.
 * \author Brian Paul
 */

/*
 * Regarding GL_NV_vertex_program, GL_NV_vertex_program1_1:
 *
 * Portions of this software may use or implement intellectual
 * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
 * any and all warranties with respect to such intellectual property,
 * including any use thereof or modifications thereto.
 */

#include "glheader.h"
#include "context.h"
#include "hash.h"
#include "imports.h"
#include "macros.h"
#include "mtypes.h"
#include "nvprogram.h"
#include "nvvertparse.h"
#include "nvvertprog.h"
#include "program.h"


/**
 * Current parsing state.  This structure is passed among the parsing
 * functions and keeps track of the current parser position and various
 * program attributes.
 */
struct parse_state {
   GLcontext *ctx;
   const GLubyte *start;
   const GLubyte *pos;
   const GLubyte *curLine;
   GLboolean isStateProgram;
   GLboolean isPositionInvariant;
   GLboolean isVersion1_1;
   GLuint inputsRead;
   GLuint outputsWritten;
   GLboolean anyProgRegsWritten;
   GLuint numInst;                 /* number of instructions parsed */
};


/*
 * Called whenever we find an error during parsing.
 */
static void
record_error(struct parse_state *parseState, const char *msg, int lineNo)
{
#ifdef DEBUG
   GLint line, column;
   const GLubyte *lineStr;
   lineStr = _mesa_find_line_column(parseState->start,
                                    parseState->pos, &line, &column);
   _mesa_debug(parseState->ctx,
               "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
               lineNo, line, column, (char *) lineStr, msg);
   _mesa_free((void *) lineStr);
#else
   (void) lineNo;
#endif

   /* Check that no error was already recorded.  Only record the first one. */
   if (parseState->ctx->Program.ErrorString[0] == 0) {
      _mesa_set_program_error(parseState->ctx,
                              parseState->pos - parseState->start,
                              msg);
   }
}


#define RETURN_ERROR							\
do {									\
   record_error(parseState, "Unexpected end of input.", __LINE__);	\
   return GL_FALSE;							\
} while(0)

#define RETURN_ERROR1(msg)						\
do {									\
   record_error(parseState, msg, __LINE__);				\
   return GL_FALSE;							\
} while(0)

#define RETURN_ERROR2(msg1, msg2)					\
do {									\
   char err[1000];							\
   _mesa_sprintf(err, "%s %s", msg1, msg2);				\
   record_error(parseState, err, __LINE__);				\
   return GL_FALSE;							\
} while(0)





static GLboolean IsLetter(GLubyte b)
{
   return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z');
}


static GLboolean IsDigit(GLubyte b)
{
   return b >= '0' && b <= '9';
}


static GLboolean IsWhitespace(GLubyte b)
{
   return b == ' ' || b == '\t' || b == '\n' || b == '\r';
}


/**
 * Starting at 'str' find the next token.  A token can be an integer,
 * an identifier or punctuation symbol.
 * \return <= 0 we found an error, else, return number of characters parsed.
 */
static GLint
GetToken(struct parse_state *parseState, GLubyte *token)
{
   const GLubyte *str = parseState->pos;
   GLint i = 0, j = 0;

   token[0] = 0;

   /* skip whitespace and comments */
   while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
      if (str[i] == '#') {
         /* skip comment */
         while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
            i++;
         }
         if (str[i] == '\n' || str[i] == '\r')
            parseState->curLine = str + i + 1;
      }
      else {
         /* skip whitespace */
         if (str[i] == '\n' || str[i] == '\r')
            parseState->curLine = str + i + 1;
         i++;
      }
   }

   if (str[i] == 0)
      return -i;

   /* try matching an integer */
   while (str[i] && IsDigit(str[i])) {
      token[j++] = str[i++];
   }
   if (j > 0 || !str[i]) {
      token[j] = 0;
      return i;
   }

   /* try matching an identifier */
   if (IsLetter(str[i])) {
      while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
         token[j++] = str[i++];
      }
      token[j] = 0;
      return i;
   }

   /* punctuation character */
   if (str[i]) {
      token[0] = str[i++];
      token[1] = 0;
      return i;
   }

   /* end of input */
   token[0] = 0;
   return i;
}


/**
 * Get next token from input stream and increment stream pointer past token.
 */
static GLboolean
Parse_Token(struct parse_state *parseState, GLubyte *token)
{
   GLint i;
   i = GetToken(parseState, token);
   if (i <= 0) {
      parseState->pos += (-i);
      return GL_FALSE;
   }
   parseState->pos += i;
   return GL_TRUE;
}


/**
 * Get next token from input stream but don't increment stream pointer.
 */
static GLboolean
Peek_Token(struct parse_state *parseState, GLubyte *token)
{
   GLint i, len;
   i = GetToken(parseState, token);
   if (i <= 0) {
      parseState->pos += (-i);
      return GL_FALSE;
   }
   len = (GLint)_mesa_strlen((const char *) token);
   parseState->pos += (i - len);
   return GL_TRUE;
}


/**
 * Try to match 'pattern' as the next token after any whitespace/comments.
 * Advance the current parsing position only if we match the pattern.
 * \return GL_TRUE if pattern is matched, GL_FALSE otherwise.
 */
static GLboolean
Parse_String(struct parse_state *parseState, const char *pattern)
{
   const GLubyte *m;
   GLint i;

   /* skip whitespace and comments */
   while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') {
      if (*parseState->pos == '#') {
         while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) {
            parseState->pos += 1;
         }
         if (*parseState->pos == '\n' || *parseState->pos == '\r')
            parseState->curLine = parseState->pos + 1;
      }
      else {
         /* skip whitespace */
         if (*parseState->pos == '\n' || *parseState->pos == '\r')
            parseState->curLine = parseState->pos + 1;
         parseState->pos += 1;
      }
   }

   /* Try to match the pattern */
   m = parseState->pos;
   for (i = 0; pattern[i]; i++) {
      if (*m != (GLubyte) pattern[i])
         return GL_FALSE;
      m += 1;
   }
   parseState->pos = m;

   return GL_TRUE; /* success */
}


/**********************************************************************/

static const char *InputRegisters[MAX_NV_VERTEX_PROGRAM_INPUTS + 1] = {
   "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
   "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
};

static const char *OutputRegisters[MAX_NV_VERTEX_PROGRAM_OUTPUTS + 1] = {
   "HPOS", "COL0", "COL1", "BFC0", "BFC1", "FOGC", "PSIZ",
   "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
};

/* NOTE: the order here must match opcodes in nvvertprog.h */
static const char *Opcodes[] = {
   "MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
   "DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
   "ABS", "END",
   /* GL_ARB_vertex_program */
   "FLR", "FRC", "EX2", "LG2", "POW", "XPD", "SWZ",
   /* Mesa-specific */
   "PRINT",
   NULL
};



/**
 * Parse a temporary register: Rnn
 */
static GLboolean
Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
{
   GLubyte token[100];

   /* Should be 'R##' */
   if (!Parse_Token(parseState, token))
      RETURN_ERROR;
   if (token[0] != 'R')
      RETURN_ERROR1("Expected R##");

   if (IsDigit(token[1])) {
      GLint reg = _mesa_atoi((char *) (token + 1));
      if (reg >= MAX_NV_VERTEX_PROGRAM_TEMPS)
         RETURN_ERROR1("Bad temporary register name");
      *tempRegNum = reg;
   }
   else {
      RETURN_ERROR1("Bad temporary register name");
   }

   return GL_TRUE;
}


/**
 * Parse address register "A0.x"
 */
static GLboolean
Parse_AddrReg(struct parse_state *parseState)
{
   /* match 'A0' */
   if (!Parse_String(parseState, "A0"))
      RETURN_ERROR;

   /* match '.' */
   if (!Parse_String(parseState, "."))
      RETURN_ERROR;

   /* match 'x' */
   if (!Parse_String(parseState, "x"))
      RETURN_ERROR;

   return GL_TRUE;
}


/**
 * Parse absolute program parameter register "c[##]"
 */
static GLboolean
Parse_AbsParamReg(struct parse_state *parseState, GLint *regNum)
{
   GLubyte token[100];

   if (!Parse_String(parseState, "c"))
      RETURN_ERROR;

   if (!Parse_String(parseState, "["))
      RETURN_ERROR;

   if (!Parse_Token(parseState, token))
      RETURN_ERROR;

   if (IsDigit(token[0])) {
      /* a numbered program parameter register */
      GLint reg = _mesa_atoi((char *) token);
      if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
         RETURN_ERROR1("Bad program parameter number");
      *regNum = reg;
   }
   else {
      RETURN_ERROR;
   }

   if (!Parse_String(parseState, "]"))
      RETURN_ERROR;

   return GL_TRUE;
}


static GLboolean
Parse_ParamReg(struct parse_state *parseState, struct vp_src_register *srcReg)
{
   GLubyte token[100];

   if (!Parse_String(parseState, "c"))
      RETURN_ERROR;

   if (!Parse_String(parseState, "["))
      RETURN_ERROR;

   if (!Peek_Token(parseState, token))
      RETURN_ERROR;

   if (IsDigit(token[0])) {
      /* a numbered program parameter register */
      GLint reg;
      (void) Parse_Token(parseState, token);
      reg = _mesa_atoi((char *) token);
      if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
         RETURN_ERROR1("Bad program parameter number");
      srcReg->File = PROGRAM_ENV_PARAM;
      srcReg->Index = reg;
   }
   else if (_mesa_strcmp((const char *) token, "A0") == 0) {
      /* address register "A0.x" */
      if (!Parse_AddrReg(parseState))
         RETURN_ERROR;

      srcReg->RelAddr = GL_TRUE;
      srcReg->File = PROGRAM_ENV_PARAM;
      /* Look for +/-N offset */
      if (!Peek_Token(parseState, token))
         RETURN_ERROR;

      if (token[0] == '-' || token[0] == '+') {
         const GLubyte sign = token[0];
         (void) Parse_Token(parseState, token); /* consume +/- */

         /* an integer should be next */
         if (!Parse_Token(parseState, token))
            RETURN_ERROR;

         if (IsDigit(token[0])) {
            const GLint k = _mesa_atoi((char *) token);
            if (sign == '-') {
               if (k > 64)
                  RETURN_ERROR1("Bad address offset");
               srcReg->Index = -k;
            }
            else {
               if (k > 63)
                  RETURN_ERROR1("Bad address offset");
               srcReg->Index = k;
            }
         }
         else {
            RETURN_ERROR;
         }
      }
      else {
         /* probably got a ']', catch it below */
      }
   }
   else {
      RETURN_ERROR;
   }

   /* Match closing ']' */
   if (!Parse_String(parseState, "]"))
      RETURN_ERROR;

   return GL_TRUE;
}


/**
 * Parse v[#] or v[<name>]
 */
static GLboolean
Parse_AttribReg(struct parse_state *parseState, GLint *tempRegNum)
{
   GLubyte token[100];
   GLint j;

   /* Match 'v' */
   if (!Parse_String(parseState, "v"))
      RETURN_ERROR;

   /* Match '[' */
   if (!Parse_String(parseState, "["))
      RETURN_ERROR;

   /* match number or named register */
   if (!Parse_Token(parseState, token))
      RETURN_ERROR;

   if (parseState->isStateProgram && token[0] != '0')
      RETURN_ERROR1("Only v[0] accessible in vertex state programs");

   if (IsDigit(token[0])) {
      GLint reg = _mesa_atoi((char *) token);
      if (reg >= MAX_NV_VERTEX_PROGRAM_INPUTS)
         RETURN_ERROR1("Bad vertex attribute register name");
      *tempRegNum = reg;
   }
   else {
      for (j = 0; InputRegisters[j]; j++) {
         if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) {
            *tempRegNum = j;
            break;
         }
      }
      if (!InputRegisters[j]) {
         /* unknown input register label */
         RETURN_ERROR2("Bad register name", token);
      }
   }

   /* Match '[' */
   if (!Parse_String(parseState, "]"))
      RETURN_ERROR;

   return GL_TRUE;
}


static GLboolean
Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
{
   GLubyte token[100];
   GLint start, j;

   /* Match 'o' */
   if (!Parse_String(parseState, "o"))
      RETURN_ERROR;

   /* Match '[' */
   if (!Parse_String(parseState, "["))
      RETURN_ERROR;

   /* Get output reg name */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -