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

📄 mal_parser.mx

📁 一个内存数据库的源代码这是服务器端还有客户端
💻 MX
📖 第 1 页 / 共 3 页
字号:
@item propQualifier  @tab :  ['@{' property '@}']@end multitableThe type ANY matches any type specifier.Appending it with an alias turns it into a type variable.The type alias is \$DIGIT (1-9) and can be used to relate typesby type equality. The type variable are defined within the context of a functionscope.Additional information, such as a repetition factor,encoding tables, or type dependency should be modelled as properties.@cint typeAlias(Client cntxt, int tpe){	int t;	if (currChar(cntxt) != TMPMARKER || tpe !=TYPE_any){		/* if( tpe == TYPE_any && currChar(cntxt)!='.' )			parseError(cntxt, "[1-9] or '...' expected\n"); */		return -1;	}	nextChar(cntxt);	t = currChar(cntxt) - '0';	if( t>9){		parseError(cntxt, "[1-9] expected\n");		return -1;	}	advance(cntxt,1);	return t;}@-The simple type analysis currently assumes a proper type identifier.We should change getTypeIndex to return a failure instead.@cint simpleTypeId(Client cntxt){	int l, tpe;	nextChar(cntxt);	l = typeidLength(cntxt);	if (l == 0) {		parseError(cntxt, "Type identifier expected\n");		return -1;	}	tpe = getTypeIndex(CURRENT(cntxt), l, -1);	if (tpe < 0) {		parseError(cntxt, "Type identifier expected\n");		return TYPE_void;	}	advance(cntxt, l);	return tpe;}int parseTypeId(Client cntxt, int defaultType){   	int i = TYPE_any, ht, tt, kh = 0, kt = 0;	char *s= CURRENT(cntxt);	if ( strncmp(s, ":bat[", 5) == 0) {		/* parse :bat[:type,:type] */		 advance(cntxt,5);		if( currChar(cntxt) ==':') {			ht = simpleTypeId(cntxt);			kh = typeAlias(cntxt,ht);		} else ht = TYPE_any;		if (currChar(cntxt) != ',') {			parseError(cntxt, "',' expected\n");			return i;		} 		nextChar(cntxt); /* skip , */		skipSpace(cntxt);		if( currChar(cntxt) ==':') {			tt = simpleTypeId(cntxt);			kt = typeAlias(cntxt,tt);		} else tt= TYPE_any;		i = newBatType(ht, tt);		if (kh > 0)			setAnyHeadIndex(i, kh);		if (kt > 0)			setAnyTailIndex(i, kt);		if (currChar(cntxt) != ']')			parseError(cntxt, "']' expected\n");		nextChar(cntxt); /* skip ']' */		skipSpace(cntxt);		return i;	}  	if( (strncmp(s,":bat",4)==0 ||		 strncmp(s,":BAT",4)==0 )  && !idCharacter[(int) s[4]]) {		advance(cntxt,4);		return TYPE_bat;	} 	if( strncmp(s,":col",4)==0 && !idCharacter[(int) s[4]]) {		/* parse default for :col[:any] */		advance(cntxt,4);		return newColType(TYPE_any);	} 	if( currChar(cntxt) ==':'){		ht = simpleTypeId(cntxt);		kt = typeAlias(cntxt,ht);		if( kt > 0)			setAnyTailIndex(ht,kt);		return ht;	} 	parseError(cntxt,"<type identifier> expected\n");	return defaultType;}INLINE int typeElm(Client cntxt, int def){	if (currChar(cntxt) != ':')		return def;	/* no type qualifier */	return parseTypeId(cntxt,def);}@-Character constants may be escaped.@cintcharCst(Client cntxt, ValPtr cst) {	int i;	str v = CURRENT(cntxt);	if (*v != '\'')		return 0;	cst->vtype = TYPE_chr;	cst->val.cval[1]= 0;	cst->val.cval[2]= 0;	cst->val.cval[3]= 0;	v++;	i = 1;	if (*v == '\\') {		v++; i++;		switch(*v){		case 'n':			cst->val.cval[0]= '\n';			break;		case 'r':			cst->val.cval[0]= '\r';		case 't':			cst->val.cval[0]= '\t';			break;		case '\\':			v++;i++;			cst->val.cval[0]= *v;			break;		default:			if (isdigit(*v)) {				i++; v++;			}			if (isdigit(*v)) {				i++; v++;			}			if (isdigit(*v)) {				i++; v++;			}			cst->val.cval[0]= (char) strtol(v,NULL,0);		}	} else {		cst->val.cval[0]= *v;		v++;	}	if (*v != '\'')		return i+1;	return i+2;}@+ The ParserThe client is responsible to collect theinput for parsing in a single string before calling the parser.Once the input is available parsing runs in a critial section fora single client thread.The parser uses the rigid structure of the language to speedupanalysis. In particular, each input line is translated intoa MAL instruction record as quickly as possible. Its context ismanipulated during the parsing process, by keeping the  curPrg,curBlk, and curInstr variables.The language statements of the parser are gradually introduced, withthe overall integration framework last.The convention is to return a zero when an error has beenreported or when the structure can not be recognized.Furthermore, we assume that blancs have been skipped before enteringrecognition of a new token.@- Module statement.The module and import commands have immediate effect.The module statement switches the location for symbol table updateto a specific named area. The effect is that all definitions may becomeglobally known (?) and symbol table should be temporarilly lockedfor updates by concurrent users.@multitable @columnfractions 0.15 0.8@item moduleStmt@tab :  @sc{atom} ident [':'ident]@item@tab | @sc{module} ident@end multitable@-An atom statement does not introduce a new module.@cstr parseAtom(Client cntxt) {	str modnme = 0,s;	int l, tpe;	char *nxt= CURRENT(cntxt);	if ( (l =idLength(cntxt)) <= 0)		return parseError(cntxt, "atom name expected\n");	/* parse: ATOM id:type */	modnme = putName(nxt, l);	advance(cntxt,l);	if (currChar(cntxt) != ':')		tpe= TYPE_void;	/* no type qualifier */	else tpe = parseTypeId(cntxt, TYPE_int);	s = loadLibrary(modnme);	if (s)		stream_printf(cntxt->fdout, "#WARNING: %s\n", s);	malAtomDefinition(modnme, tpe);	cntxt->nspace = fixModule(cntxt->nspace, modnme);	cntxt->nspace->isAtomModule = TRUE;	@:helpInfo(cntxt->nspace->help) @	return "";}str parseModule(Client cntxt) {	str modnme = 0,s;	int l;	char *nxt;	nxt= CURRENT(cntxt);	if ((l = idLength(cntxt)) <= 0)		return parseError(cntxt, "<module path> expected\n");	modnme = putName(nxt, l);	s = loadLibrary(modnme);	if (s)		stream_printf(cntxt->fdout, "#WARNING: %s\n", s);	advance(cntxt,l);	cntxt->nspace = fixModule(cntxt->nspace, modnme);	@:helpInfo(cntxt->nspace->help)@	return "";}@- Include statementAn include statement is immediately taken into effect. Thiscalls for temporary switching the input for a particular client.The administration for this is handled by malInclude.No listing is produced, because module sources are assumed tobe debugged upfront already.@multitable @columnfractions 0.15 0.8@item includeStmt@tab : @sc{include} identifier @item@tab | @sc{include} string_literal@end multitable@cstrparseInclude(Client cntxt){	str modnme = 0,s;	int x;	char *nxt;	if (!MALkeyword(cntxt,"include",7)) 		return 0;	nxt= CURRENT(cntxt);	if ( (x = idLength(cntxt)) >0 ){		modnme= putName(nxt,x);		advance(cntxt,x);	} else	if ( (x = stringLength(cntxt))>0){		modnme= putName(nxt+1,x-1);		advance(cntxt,x);	} else		return parseError(cntxt,"<module name> expected\n");	if (currChar(cntxt) != ';') {		parseError(cntxt,"';' expected\n");		skipToEnd(cntxt);		return "";	}	skipToEnd(cntxt);	s = loadLibrary(modnme);	if (s)		stream_printf(cntxt->fdout, "#WARNING: %s\n", s);	malInclude(cntxt, modnme, 0);	return "";}@- DefinitionThe definition statements share a lot in common, which calls for factoringout the code in a few text macros. Upon encountering a definition, weinitialize a MAL instruction container. We should also check fornon-terminated definitions.@multitable @columnfractions 0.15 0.8@item program@tab : ( definition [helpinfo] | statement ) *@item definition@tab : moduleStmt | includeStmt @item@tab  |  commandStmt | patternStmt @item@tab  | functionStmt | factoryStmt@item@tab  | includeStmt@end multitableBeware, a function signature f(a1..an):(b1..bn) is parsed in such a way thatthe symbol table and stackframe contains the sequencef,a1..an,b1..bn. This slightly complicates the implementationof the return statement.Note, the function name could be mod.fcn, which calls for storingthe function definition in a particular module instead of the current one.@= fcnHeader	l = operatorLength(cntxt);	if (l == 0)		l = idLength(cntxt);	if (l == 0)		return (MalBlkPtr) parseError(cntxt,				"<identifier> | <operator> expected\n");	fnme= putName( ((char *) CURRENT(cntxt)),l);	advance(cntxt,l);	if (currChar(cntxt) == '.') {		nextChar(cntxt); /* skip '.' */		modnme = fnme;		l= operatorLength(cntxt);		if (l == 0)			l = idLength(cntxt);		if (l == 0)			return (MalBlkPtr) parseError(cntxt,					"<identifier> | <operator> expected\n");		fnme= putName( ((char *) CURRENT(cntxt)),l);		advance(cntxt,l);	} 	/* temporary suspend capturing statements in main block */	if( cntxt->backup && curBlk && curBlk->errors==0) 		GDKfatal("mal_parser: unexpected recursion\n");	cntxt->backup = cntxt->curprg;	cntxt->curprg = newFunction(fnme, kind);	curPrg = cntxt->curprg;		curBlk = curPrg->def;	curBlk->flowfixed= 0;	curBlk->typefixed= 0;	curInstr = getInstrPtr(curBlk,0);	@:propList(curInstr->argv[0])@	if (currChar(cntxt) != '(') 		return (MalBlkPtr)parseError(cntxt, "function header '(' expected\n"); 	advance(cntxt,1);	setModuleId(curInstr, modnme?putName(modnme,strlen(modnme)): 			putName(cntxt->nspace->name, strlen(cntxt->nspace->name)));	/* get calling parameters */	ch= currChar(cntxt);	while( ch !=')' && ch && !NL(ch)){		@:binding(1)@		/* the last argument may be variable length */		if( MALkeyword(cntxt,"...",3) ){			curInstr->varargs |= VARARGS;			setPolymorphic(curInstr,TYPE_any,FALSE);			break;		}		if ((ch = currChar(cntxt)) != ',') {			if (ch == ')')				break;			return (MalBlkPtr) parseError(cntxt,"',' expected\n");		} else 			nextChar(cntxt); /* skip ',' */		skipSpace(cntxt);		ch = currChar(cntxt);	}	if (currChar(cntxt) != ')') {		freeInstruction(curInstr);		return (MalBlkPtr) parseError(cntxt,"')' expected\n");	}	advance(cntxt,1); /* skip ')' *//*The return type is either a single type or multiple return type structure.We simply keep track of the number of arguments added andduring the final phase reshuffle the return values to the beginning (?)*/	if (currChar(cntxt)== ':'){		type = typeElm(cntxt, TYPE_void);		setPolymorphic(curInstr,type,TRUE);		setVarType(curBlk,curInstr->argv[0],type);		/* we may be confronted by a variable target type list */		if( MALkeyword(cntxt,"...",3) ){			curInstr->varargs |= VARRETS;			setPolymorphic(curInstr,TYPE_any,FALSE);		}				@:propList(curInstr->argv[0])@	} else 	if( keyphrase1(cntxt,"(")){ /* deal with compound return */		int retc= curInstr->argc, i1,i2=0;		int maxarg;		int *newarg;		/* parse multi-target result */		/* skipSpace(cntxt);*/		ch= currChar(cntxt);		while( ch !=')' && ch && !NL(ch)){			int varid=0;			int type= TYPE_any;			@:binding(0)@			if( (ch=currChar(cntxt)) != ',') {				 if( ch==')') break;				 return (MalBlkPtr) parseError(cntxt, "',' expected\n");			} else {				nextChar(cntxt); /* skip ',' */ 			}			skipSpace(cntxt);			ch = currChar(cntxt);		}		/* re-arrange the parameters, results first*/		maxarg= curInstr->maxarg;		newarg= (int*)GDKmalloc(maxarg*sizeof(int));		for(i1= retc; i1<curInstr->argc; i1++)			newarg[i2++]= curInstr->argv[i1];		curInstr->retc= curInstr->argc-retc;		for(i1= 1; i1<retc; i1++)			newarg[i2++]= curInstr->argv[i1];		curInstr->argc= i2;		for(; i2<maxarg; i2++) newarg[i2]= 0;		for(i1=0; i1<maxarg; i1++) 			curInstr->argv[i1] = newarg[i1];		GDKfree(newarg);		if (currChar(cntxt) != ')') {			freeInstruction(curInstr);			return (MalBlkPtr) parseError(cntxt, "')' expected\n");		}		nextChar(cntxt); /* skip ')' */	} else { /* default */		setVarType(curBlk,0,TYPE_void);	}@-The common theme in definitions is to parse the argument list.@multitable @columnfractions .15 .8@item header@tab :  hdrName '(' params ')' result @item result@tab :  paramType | '(' params ')'@item params@tab :  binding [',' binding]* @item binding@tab :  identifier typeName [propQualifier]@end multitable@@= binding	l = idLength(cntxt);	if( l>0) {		varid = findVariableLength(curBlk, CURRENT(cntxt), l);		if( varid < 0){			varid = newVariable(curBlk,idCopy(cntxt,l),TYPE_any);			type= typeElm(cntxt,TYPE_any);			if( isPolymorphic(type) )				setPolymorphic(curInstr,type,TRUE);			setVarType(curBlk,varid,type);			@:propList(varid)@		} else 		if( @1){			parseError(cntxt,"Argument defined twice\n");			typeElm(cntxt,getVarType(curBlk,varid));			@:propList(varid)@		} else {			advance(cntxt,l);			type= typeElm(cntxt,getVarType(curBlk,varid));			if( type != getVarType(curBlk,varid))				parseError(cntxt,"Incompatible argument type\n");			if( isPolymorphic(type) )				setPolymorphic(curInstr,type,TRUE);			setVarType(curBlk,varid,type);			@:propList(varid)@		}	} else if( currChar(cntxt)== ':' ){		type= typeElm(cntxt,TYPE_any);		varid = newTmpVariable(curBlk,type);		if( isPolymorphic(type) )			setPolymorphic(curInstr,type,TRUE);		setVarType(curBlk,varid,type);		@:propList(varid)@	} else 		parseError(cntxt,"argument expected\n");	curInstr= pushArgument(curBlk,curInstr, varid);@-@}MAL variables are statically/dynamically typed.Function and procedure arguments should always be typed.We do not permit polymorphism at this interpretation level.The type information maintained simplifies analysis of BAT results. If the underlying type is not known, then itmay be replaced once during execution of a MAL instructiontypically as a side-effect of calling a bat-returning function.We should also allow for variable argument lists. However, theymay only appear in patterns, because the calling context is necessaryto resolve the actual argument list. Furthermore, we can not assume much about its type structure.@-Variables are extended with a property list to enableoptimizers to make decisions. (See the section on properties).@{@-@= propList	if( keyphrase1(cntxt,"{")) {		do {			str pname,opname;			int i,lo;			ValRecord cst;			l = idLength(cntxt);			if(l==0) 				break;			pname= idCopy(cntxt,l);			if( curBlk->var[@1]->props== NULL)				 curBlk->var[@1]->props= newPropertySet();			/* localize value , simplified version */			lo= operatorLength(cntxt);			if( lo > 0) 				opname= operatorCopy(cntxt,lo);			else opname= GDKstrdup("");			if((i= cstToken(cntxt,&cst))){				setVarProperty(curBlk,@1, pname, opname, &cst);				advance(cntxt,i);			} else 				setVarProperty(curBlk,@1, pname, NULL, NULL);			GDKfree(pname); 			GDKfree(opname); 		} while( keyphrase1(cntxt,","));		if( !keyphrase1(cntxt,"}") )			/* return (MalBlkPtr) */			parseError(cntxt,"'}' expected\n");	}@-Each procedure definition opens a structure in which theinformation is gathered. The enclosing module is staticallydetermined.A proc-header translates into a single MAL instruction.Since no recursive rules are included, we can stick tousing a single global variable to accummulate theproperties.The external commands and rules come with a shorthelp information.@= helpInfo	if( MALkeyword(cntxt,"comment",7)){		if( (l= stringLength(cntxt))){			@1 = strCopy(cntxt,l);			advance(cntxt,l);		} else {			parseError(cntxt,"<string> expected\n");		}	} else 	if (currChar(cntxt) != ';')		parseError(cntxt,"';' expected\n");	skipToEnd(cntxt);@cMalBlkPtr parseCommandPattern(Client cntxt, int kind){	MalBlkPtr curBlk = 0;	Symbol curPrg = 0;	InstrPtr curInstr=0;	int l;	str fnme=0, modnme=0;	char ch;	int varid=0;	int type= TYPE_void;	@:fcnHeader@	getInstrPtr(curBlk,0)->token= kind;	curPrg->kind = kind;	modnme= modnme? modnme:cntxt->nspace->name;	insertSymbol(findModule(cntxt->nspace, 			putName(modnme,strlen(modnme))), curPrg);	trimMalBlk(curBlk);	chkProgram(cntxt->nspace,curBlk);	if( cntxt->backup){		cntxt->curprg = cntxt->backup;		cntxt->backup = 0;	}@- Short-cut function callsMost functions are (dynamically) linked with the kernel as

⌨️ 快捷键说明

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