--- /dev/null
+/*
+famicom ROM cartridge utility - unagi
+script syntax data and function
+
+Copyright (C) 2008-2009 ±·³«È¯¶¨Æ±Áȹç
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include "type.h"
+#include "textutil.h"
+#include "script.h"
+#include "script_syntax.h"
+
+static int syntax_check_expression(char **word, int word_num, struct st_expression *e)
+{
+ if(word_num == 0){
+ return NG;
+ }
+ //left
+ if(value_get(word[0], &(e->left.value)) == OK){
+ e->left.type = EXPRESSION_TYPE_VALUE;
+ }else{
+ e->left.type = EXPRESSION_TYPE_VARIABLE;
+ e->left.variable = word[0][0];
+ }
+ word_num--;
+ if(word_num == 0){
+ e->operator = OPERATOR_NONE;
+ return OK;
+ }
+ //operator
+ e->operator = operator_get(word[1]);
+ if(e->operator == OPERATOR_ERROR){
+ return NG;
+ }
+ word_num--;
+ if(word_num == 0){
+ return NG;
+ }
+ //right
+ if(value_get(word[2], &(e->right.value)) == OK){
+ e->right.type = EXPRESSION_TYPE_VALUE;
+ }else{
+ e->right.type = EXPRESSION_TYPE_VARIABLE;
+ e->right.variable = word[2][0];
+ }
+ return OK;
+}
+
+static int strto_enum(const char **t, const char *word, int start, long *val)
+{
+ long i = start;
+ while(*t != NULL){
+ if(strcmp(*t, word) == 0){
+ *val = i;
+ return OK;
+ }
+ i++;
+ t++;
+ }
+ return NG;
+}
+
+#include "syntax_data.h"
+static const char SYNTAX_ERROR_PREFIX[] = "syntax error:";
+
+/*
+return: error count, ¤³¤³¤Ç¤Ï 0 or 1
+*/
+static int syntax_check_phase(char **word, int word_num, struct script *s, const int mode)
+{
+ int i = sizeof(SCRIPT_SYNTAX) / sizeof(SCRIPT_SYNTAX[0]);
+ const struct script_syntax *syntax;
+ const char *opword;
+ opword = word[0];
+ syntax = SCRIPT_SYNTAX;
+ while(i != 0){
+ if(strcmp(syntax->name, opword) == 0){
+ int j;
+
+ s->opcode = syntax->script_opcode;
+ if((mode & syntax->permittion) == 0){
+ printf("%d:%s opcode %s is not allowed on current mode\n", s->line, SYNTAX_ERROR_PREFIX, syntax->name);
+ return 1;
+ };
+ {
+ int compare = 0;
+ switch(syntax->compare){
+ case SYNTAX_COMPARE_EQ:
+ compare = (syntax->argc == (word_num - 1));
+ break;
+ case SYNTAX_COMPARE_GT:
+ compare = ((word_num - 1) >= syntax->argc);
+ compare &= (word_num <= 5);
+ break;
+ }
+ if(!compare){
+ printf("%d:%s parameter number not match %s\n", s->line, SYNTAX_ERROR_PREFIX, opword);
+ return 1;
+ }
+ }
+ //opcode pointer ¤ò¤º¤é¤·¤Æñ¸ì¤Îµ¯ÅÀ¤ò°ú¿ô¤À¤±¤Ë¤¢¤ï¤»¤ë
+ word++;
+ word_num--;
+ for(j = 0; j < word_num; j++){
+ switch(syntax->argv_type[j]){
+ case SYNTAX_ARGVTYPE_NULL:
+ printf("%d:%s ARGV_NULL select\n", s->line, SYNTAX_ERROR_PREFIX);
+ return 1;
+ case SYNTAX_ARGVTYPE_VALUE:
+ if(value_get(word[j], &(s->value[j])) == NG){
+ printf("%d:%s value error %s %s\n", s->line, SYNTAX_ERROR_PREFIX, opword, word[j]);
+ return 1;
+ }
+ break;
+ case SYNTAX_ARGVTYPE_HV:
+ switch(word[j][0]){
+ case 'H':
+ case 'h':
+ s->value[j] = MIRROR_HORIZONAL;
+ break;
+ case 'V':
+ case 'v':
+ s->value[j] = MIRROR_VERTICAL;
+ break;
+ case 'A':
+ case 'a':
+ s->value[j] = MIRROR_PROGRAMABLE;
+ break;
+ default:
+ printf("%d:%s unknown scroll mirroring type %s\n", s->line, SYNTAX_ERROR_PREFIX, word[j]);
+ return 1;
+ }
+ break;
+ case SYNTAX_ARGVTYPE_EXPRESSION:
+ s->value[j] = VALUE_EXPRESSION;
+ //Ì¿Îá̾¤Îñ¸ì¤Èñ¸ì¿ô¤ò½ü³°¤·¤ÆÅϤ¹
+ if(syntax_check_expression(&word[j], word_num - 1, &s->expression) == NG){
+ printf("%d:%s expression error\n", s->line, SYNTAX_ERROR_PREFIX);
+ return 1;
+ }
+ //°Ü¹Ô¤Îñ¸ì¤ÏÆɤޤʤ¤¤³¤È¤Ë¤¹¤ë(¤Þ¤º¤¤¤«¤â)
+ return 0;
+ case SYNTAX_ARGVTYPE_VARIABLE:{
+ const char v = word[j][0];
+ if(v >= 'a' && v <= 'z'){
+ s->value[j] = VALUE_VARIABLE;
+ s->variable = v;
+ }else{
+ printf("%d:%s variable must use [a-z] %s\n", s->line, SYNTAX_ERROR_PREFIX, word[j]);
+ return 1;
+ }
+ }break;
+ case SYNTAX_ARGVTYPE_CONSTANT:{
+ if(value_get(word[j], &(s->value[j])) == OK){
+ break;
+ }else if(strto_enum(STR_CONSTANTNAME, word[j], VALUE_CONTANT_CPU_STEP_START, &(s->value[j])) == OK){
+ break;
+ }else{
+ printf("%d:%s constant error %s %s\n", s->line, SYNTAX_ERROR_PREFIX, opword, word[j]);
+ return 1;
+ }
+ }break;
+ case SYNTAX_ARGVTYPE_TRANSTYPE:{
+ if(strto_enum(STR_TRANSTYPE, word[j], VALUE_TRANSTYPE_EMPTY, &(s->value[j])) == NG){
+ printf("%d:%s unknown trans type %s\n", s->line, SYNTAX_ERROR_PREFIX, word[j]);
+ return 1;
+ }
+ }break;
+ default:
+ s->value[j] = VALUE_UNDEF;
+ break;
+ }
+ }
+ //opcode found and ÆþÎÏʸ»ú¼ïÀµ¾ï
+ return 0;
+ }
+ syntax++;
+ i--;
+ }
+ printf("%d:%s unknown opcode %s\n", s->line, SYNTAX_ERROR_PREFIX, opword);
+ return 1;
+}
+
+/*
+return: error count
+*/
+int syntax_check(char **text, int text_num, struct script *s, int mode)
+{
+ int error = 0;
+ int i;
+ mode = 1<< mode; //permittion ¤Ï bitflag ¤Ê¤Î¤Ç¤³¤³¤ÇÊÑ´¹¤¹¤ë
+ for(i = 0; i < text_num; i++){
+ char *word[TEXT_MAXWORD];
+ const int n = word_load(text[i], word);
+ s->line = i + 1;
+ switch(word[0][0]){
+ case '#':
+ case '\0':
+ s->opcode = SCRIPT_OPCODE_COMMENT;
+ break;
+ default:
+ error += syntax_check_phase(word, n, s, mode);
+ break;
+ }
+ s++;
+ }
+ return error;
+}
+