Пример #1
0
void ParseParamList()
{
  if(Token!=TOK_CLOSE)
  {
    ParseTypeAndName();
    while(Token==TOK_COMMA)
    {
      Match(TOK_COMMA);
      if(Token==TOK_ELIPSIS)
      {
        Match();
        break;
      }
      else
      {
        ParseTypeAndName();
      }
    }
  }
}
Пример #2
0
/*
 * Parse an operation definition.
 *
 * Operation ::= %operation { OperFlag } Type [ClassName ] IDENTIFIER
 *                  '(' [ Params ] ')' [ '=' LITERAL_CODE ] [ ';' ]
 * OperFlag ::= %virtual | %inline
 * ClassName ::= IDENTIFIER "::"
 * Params ::= Param { ',' Param }
 * Param ::= TypeAndName | '[' TypeAndName ']'
 */
static void ParseOperation(TreeCCContext *context)
{
	TreeCCInput *input = context->input;
	int flags;
	char *returnType;
	char *name;
	char *className;
	char *defValue;
	TreeCCParam *params = 0;
	TreeCCParam *lastParam = 0;
	TreeCCParam *newParam;
	int numTriggers = 0;
	char *paramType;
	char *paramName;
	int paramFlags;
	TreeCCOperation *oper;
	char *filename;
	long linenum;
	TreeCCNode *typeNode;

	/* Skip the "%operation" keyword */
	TreeCCNextToken(input);

	/* Parse the operation flags */
	flags = 0;
	for(;;)
	{
		if(input->token == TREECC_TOKEN_VIRTUAL)
		{
			flags |= TREECC_OPER_VIRTUAL;
			TreeCCNextToken(input);
		}
		else if(input->token == TREECC_TOKEN_INLINE)
		{
			flags |= TREECC_OPER_INLINE;
			TreeCCNextToken(input);
		}
		else if(input->token == TREECC_TOKEN_SPLIT)
		{
			flags |= TREECC_OPER_SPLIT;
			TreeCCNextToken(input);
		}
		else
		{
			break;
		}
	}
	if((flags & TREECC_OPER_VIRTUAL) != 0 &&
	   (flags & TREECC_OPER_INLINE) != 0)
	{
		TreeCCError(input, "`virtual' and `inline' cannot be used together");
		flags &= ~TREECC_OPER_INLINE;
	}

	/* Parse the return type and name of the operation */
	ParseTypeAndName(input, &returnType, &name);
	filename = input->filename;
	linenum = input->linenum;
	if(!returnType || !name)
	{
		if(returnType)
		{
			TreeCCError(input, "operation name expected");
		}
		else
		{
			TreeCCError(input, "operation return type expected");
		}
		if(returnType)
		{
			free(returnType);
		}
		if(name)
		{
			free(name);
		}
		return;
	}

	/* If the next token is "::", then "name" is actually the
	   class name and we need to get the real operation name */
	if(input->token == TREECC_TOKEN_COLON_COLON)
	{
		className = name;
		TreeCCNextToken(input);
		if(input->token != TREECC_TOKEN_IDENTIFIER)
		{
			TreeCCError(input, "operation name expected");
			free(returnType);
			free(className);
			return;
		}
		name = TreeCCValue(input);
		TreeCCNextToken(input);
	}
	else
	{
		className = 0;
	}

	/* If the operation is non-virtual, and the language is C#,
	   then we must have a class name which is different from
	   the operation name.  This is necessary because of a
	   "feature" in the design of C# and Microsoft's compilers */
	if((flags & TREECC_OPER_VIRTUAL) == 0 &&
	   context->language == TREECC_LANG_CSHARP)
	{
		if(!className)
		{
			TreeCCErrorOnLine(input, filename, linenum,
							  "C# requires that a class name be specified");
		}
		else if(!strcmp(className, name))
		{
			TreeCCErrorOnLine(input, filename, linenum,
				  "C# requires different class and operation names");
		}
	}

	/* Parse the parameter list for the operation */
	if(input->token == TREECC_TOKEN_LPAREN)
	{
		TreeCCNextToken(input);
		while(input->token == TREECC_TOKEN_IDENTIFIER ||
		      input->token == TREECC_TOKEN_LSQUARE)
		{
			/* Parse the parameter information */
			if(input->token == TREECC_TOKEN_IDENTIFIER)
			{
				paramFlags = 0;
				ParseTypeAndName(input, &paramType, &paramName);
			}
			else
			{
				paramFlags = TREECC_PARAM_TRIGGER;
				TreeCCNextToken(input);
				ParseTypeAndName(input, &paramType, &paramName);
				if(input->token == TREECC_TOKEN_RSQUARE)
				{
					TreeCCNextToken(input);
				}
				else
				{
					TreeCCError(input, "`]' expected");
				}
				++numTriggers;
			}

			/* Create the parameter block */
			if(!paramType)
			{
				TreeCCError(input, "parameter declaration expected");
			}
			else if(!strcmp(paramType, "void"))
			{
				/* Ignore "void" parameters */
				free(paramType);
				if(paramName)
				{
					free(paramName);
				}
			}
			else
			{
				newParam = (TreeCCParam *)malloc(sizeof(TreeCCParam));
				if(!newParam)
				{
					TreeCCOutOfMemory(input);
				}
				newParam->name = paramName;
				newParam->type = paramType;
				newParam->flags = paramFlags;
				newParam->size = 0;
				newParam->next = 0;
				if(lastParam)
				{
					lastParam->next = newParam;
				}
				else
				{
					params = newParam;
				}
				lastParam = newParam;
				if((paramFlags & TREECC_PARAM_TRIGGER) != 0)
				{
					if((typeNode = TreeCCNodeFindByType(context, paramType))
								== 0)
					{
						TreeCCError(input, "`%s' is not a valid trigger type",
									paramType);
					}
					else
					{
						ValidateSuffixes(context, paramType, typeNode,
										 input->filename, input->linenum);
					}
				}
			}

			/* Skip the comma and go on to the next parameter */
			if(input->token == TREECC_TOKEN_COMMA)
			{
				TreeCCNextToken(input);
				if(input->token != TREECC_TOKEN_IDENTIFIER &&
				   input->token != TREECC_TOKEN_LSQUARE)
				{
					TreeCCError(input, "parameter declaration expected");
				}
			}
			else
			{
				break;
			}
		}
		if(input->token == TREECC_TOKEN_RPAREN)
		{
			TreeCCNextToken(input);
		}
		else
		{
			TreeCCError(input, "`)' expected");
		}
	}
	else
	{
		TreeCCError(input, "`(' expected");
	}

	/* Recognise the default value, if present */
	if(input->token == TREECC_TOKEN_EQUALS)
	{
		TreeCCNextToken(input);
		if(input->token == TREECC_TOKEN_LITERAL_CODE)
		{
			defValue = TreeCCValue(input);
			TreeCCNextToken(input);
		}
		else
		{
			TreeCCError(input, "default value expected");
			defValue = 0;
		}
	}
	else
	{
		defValue = 0;
		if((flags & TREECC_OPER_VIRTUAL) == 0 &&
		   strcmp(returnType, "void") != 0)
		{
			TreeCCError(input, "default value required");
		}
	}

	/* Recognise an optional semi-colon */
	if(input->token == TREECC_TOKEN_SEMI)
	{
		TreeCCNextToken(input);
	}

	/* Set a default trigger parameter if necessary */
	if(numTriggers == 0 && params != 0)
	{
		numTriggers = 1;
		params->flags |= TREECC_PARAM_TRIGGER;
		if((typeNode = TreeCCNodeFindByType(context, params->type)) == 0)
		{
			TreeCCErrorOnLine(input, filename, linenum,
							  "`%s' is not a valid trigger type",
							  params->type);
		}
		else
		{
			ValidateSuffixes(context, params->type, typeNode,
							 filename, linenum);
		}
	}

	/* If the operation is virtual, then check that the first
	   parameter is the sole trigger for the operation */
	if((flags & TREECC_OPER_VIRTUAL) != 0)
	{
		if(!params || numTriggers != 1 ||
		   (params->flags & TREECC_PARAM_TRIGGER) == 0)
		{
			if(!params)
			{
				TreeCCError(input,
					"virtual operations must have at least one parameter");
			}
			else
			{
				TreeCCError(input,
					"the first parameter of a virtual must be the trigger");
			}
			flags &= ~TREECC_OPER_VIRTUAL;
		}
		else if((typeNode = TreeCCNodeFindByType(context, params->type)) == 0)
		{
			flags &= ~TREECC_OPER_VIRTUAL;
		}
		else if((typeNode->flags & TREECC_NODE_ENUM) != 0)
		{
			TreeCCError(input,
			  "cannot use enumerated types as triggers for virtual operations");
			flags &= ~TREECC_OPER_VIRTUAL;
		}
	}

	/* See if we already have an operation with this name */
	oper = TreeCCOperationFind(context, name);
	if(oper != 0)
	{
		TreeCCErrorOnLine(input, filename, linenum,
						  "operation `%s' is already declared", name);
		TreeCCErrorOnLine(input, oper->filename, oper->linenum,
						  "previous declaration here");
		free(returnType);
		free(name);
		if(className)
		{
			free(className);
		}
		if(defValue)
		{
			free(defValue);
		}
		while(params != 0)
		{
			newParam = params->next;
			if(params->name)
			{
				free(params->name);
			}
			if(params->type)
			{
				free(params->type);
			}
			free(params);
			params = newParam;
		}
		return;
	}

	/* Create the operation */
	oper = TreeCCOperationCreate(context, returnType, name, className,
								 defValue, params, flags, numTriggers,
								 filename, linenum);

	/* If the operation is virtual, then attach it to the node type */
	if((flags & TREECC_OPER_VIRTUAL) != 0)
	{
		TreeCCNodeAddVirtual
			(context, TreeCCNodeFindByType(context, params->type), oper);
	}
}
Пример #3
0
/*
 * Parse a node definition.
 *
 * Node ::= %node IDENTIFIER [ IDENTIFIER ] { NodeFlag } [ "=" Fields ]
 * NodeFlag ::= %abstract | %typedef
 * Fields ::= "{" { Field } "}"
 * Field ::= [ %nocreate ] TypeAndName [ "=" LITERAL_CODE ] ";"
 */
static void ParseNode(TreeCCContext *context)
{
	TreeCCInput *input = context->input;
	char *name;
	char *parent;
	int flags;
	long linenum;
	TreeCCNode *node;
	char *fieldName;
	char *fieldType;
	char *fieldValue;

	/* Skip the "%node" keyword */
	TreeCCNextToken(input);
	linenum = input->linenum;

	/* We need an identifier for the node that is being declared */
	if(input->token != TREECC_TOKEN_IDENTIFIER)
	{
		/* Report an error for the identifier */
		TreeCCError(input, "identifier expected");
		return;
	}
	name = TreeCCValue(input);
	TreeCCNextToken(input);

	/* Get the name of the parent */
	if(input->token == TREECC_TOKEN_IDENTIFIER)
	{
		parent = TreeCCValue(input);
		TreeCCNextToken(input);
	}
	else
	{
		parent = 0;
	}

	/* Parse the node definition flags */
	flags = 0;
	for(;;)
	{
		if(input->token == TREECC_TOKEN_ABSTRACT)
		{
			flags |= TREECC_NODE_ABSTRACT;
			TreeCCNextToken(input);
		}
		else if(input->token == TREECC_TOKEN_TYPEDEF)
		{
			flags |= TREECC_NODE_TYPEDEF;
			TreeCCNextToken(input);
		}
		else
		{
			break;
		}
	}

	/* Create the node */
	node = TreeCCNodeCreate(context, linenum, name, parent, flags);

	/* If we have a field definition block, then read it */
	if(input->token == TREECC_TOKEN_EQUALS)
	{
		input->parseLiteral = 0;
		TreeCCNextToken(input);
		input->parseLiteral = 1;
		if(input->token == TREECC_TOKEN_LBRACE)
		{
			/* Skip the "{" token */
			TreeCCNextToken(input);

			/* Process the field definitions */
			while(input->token != TREECC_TOKEN_RBRACE &&
				  input->token != TREECC_TOKEN_EOF)
			{
				/* Skip spurious semi-colons in the field definition */
				if(input->token == TREECC_TOKEN_SEMI)
				{
					TreeCCNextToken(input);
					continue;
				}

				/* Process field definition flags */
				if(input->token == TREECC_TOKEN_NOCREATE)
				{
					flags = TREECC_FIELD_NOCREATE;
					TreeCCNextToken(input);
				}
				else
				{
					flags = 0;
				}

				/* Parse the field type and name */
				ParseTypeAndName(input, &fieldType, &fieldName);
				if(fieldType && fieldName)
				{
					if(input->token == TREECC_TOKEN_EQUALS)
					{
						TreeCCNextToken(input);
						if(input->token == TREECC_TOKEN_LITERAL_CODE)
						{
							fieldValue = TreeCCValue(input);
							TreeCCNextToken(input);
						}
						else
						{
							TreeCCError
								(input, "literal code constant expected");
							fieldValue = 0;
						}
					}
					else
					{
						fieldValue = 0;
					}
					if(fieldValue && (flags & TREECC_FIELD_NOCREATE) == 0)
					{
						TreeCCError(input,
							"default values can only be specified for "
							"`%%nocreate' fields");
					}
					TreeCCFieldCreate(context, node, fieldName, fieldType,
									  fieldValue, flags);
				}
				else
				{
					if(fieldType)
					{
						TreeCCError(input, "field name expected");
					}
					else
					{
						TreeCCError(input, "field declaration expected");
					}
					if(fieldType)
					{
						free(fieldType);
					}
					if(fieldName)
					{
						free(fieldName);
					}

					/* Attempt to recover from the error */
					while(input->token != TREECC_TOKEN_SEMI &&
						  input->token != TREECC_TOKEN_RBRACE &&
						  input->token != TREECC_TOKEN_IDENTIFIER &&
						  input->token != TREECC_TOKEN_EOF)
					{
						TreeCCNextToken(input);
					}
				}

				/* Recognize the ";" at the end of the field */
				if(input->token == TREECC_TOKEN_SEMI)
				{
					TreeCCNextToken(input);
				}
				else
				{
					/* Attempt to recover from the lack of a semi-colon */
					TreeCCError(input, "`;' expected");
					if(input->token != TREECC_TOKEN_IDENTIFIER &&
					   input->token != TREECC_TOKEN_RBRACE)
					{
						TreeCCNextToken(input);
					}
				}
			}

			/* Skip the "}" token */
			TreeCCNextToken(input);
		}
		else
		{
			TreeCCError(input, "field definition block expected");
		}
	}
}