📄 nvvertparse.c
字号:
/*
* 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 + -