| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | // Copyright 2009 The Go Authors.  All rights reserved. | 
					
						
							|  |  |  | // Use of this source code is governed by a BSD-style | 
					
						
							|  |  |  | // license that can be found in the LICENSE file. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package Scanner | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-11 09:45:40 -07:00
										 |  |  | import Platform "platform" | 
					
						
							| 
									
										
										
										
											2008-07-30 17:36:03 -07:00
										 |  |  | import Utils "utils" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-11 09:45:40 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-04 10:19:36 -07:00
										 |  |  | export const ( | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	ILLEGAL = iota; | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	EOF; | 
					
						
							| 
									
										
										
										
											2008-08-05 18:52:37 -07:00
										 |  |  | 	INT; | 
					
						
							|  |  |  | 	FLOAT; | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	STRING; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	COMMA; | 
					
						
							|  |  |  | 	COLON; | 
					
						
							|  |  |  | 	SEMICOLON; | 
					
						
							|  |  |  | 	PERIOD; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	LPAREN; | 
					
						
							|  |  |  | 	RPAREN; | 
					
						
							|  |  |  | 	LBRACK; | 
					
						
							|  |  |  | 	RBRACK; | 
					
						
							|  |  |  | 	LBRACE; | 
					
						
							|  |  |  | 	RBRACE; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	ASSIGN; | 
					
						
							|  |  |  | 	DEFINE; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	INC; | 
					
						
							|  |  |  | 	DEC; | 
					
						
							|  |  |  | 	NOT; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	AND; | 
					
						
							|  |  |  | 	OR; | 
					
						
							|  |  |  | 	XOR; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	ADD; | 
					
						
							|  |  |  | 	SUB; | 
					
						
							|  |  |  | 	MUL; | 
					
						
							|  |  |  | 	QUO; | 
					
						
							|  |  |  | 	REM; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	EQL; | 
					
						
							|  |  |  | 	NEQ; | 
					
						
							|  |  |  | 	LSS; | 
					
						
							|  |  |  | 	LEQ; | 
					
						
							|  |  |  | 	GTR; | 
					
						
							|  |  |  | 	GEQ; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	SHL; | 
					
						
							|  |  |  | 	SHR; | 
					
						
							| 
									
										
										
										
											2008-07-16 17:00:48 -07:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-09-17 13:05:39 -07:00
										 |  |  | 	ARROW; | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ADD_ASSIGN; | 
					
						
							|  |  |  | 	SUB_ASSIGN; | 
					
						
							|  |  |  | 	MUL_ASSIGN; | 
					
						
							|  |  |  | 	QUO_ASSIGN; | 
					
						
							|  |  |  | 	REM_ASSIGN; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AND_ASSIGN; | 
					
						
							|  |  |  | 	OR_ASSIGN; | 
					
						
							|  |  |  | 	XOR_ASSIGN; | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	SHL_ASSIGN; | 
					
						
							|  |  |  | 	SHR_ASSIGN; | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-10 14:42:33 -07:00
										 |  |  | 	LAND; | 
					
						
							|  |  |  | 	LOR; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-08-11 20:40:37 -07:00
										 |  |  | 	// IDENT must be immediately before keywords | 
					
						
							|  |  |  | 	IDENT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	// keywords | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	KEYWORDS_BEG; | 
					
						
							|  |  |  | 	BREAK; | 
					
						
							|  |  |  | 	CASE; | 
					
						
							| 
									
										
										
										
											2008-07-07 17:27:14 -07:00
										 |  |  | 	CHAN; | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	CONST; | 
					
						
							|  |  |  | 	CONTINUE; | 
					
						
							|  |  |  | 	DEFAULT; | 
					
						
							|  |  |  | 	ELSE; | 
					
						
							|  |  |  | 	EXPORT; | 
					
						
							|  |  |  | 	FALLTHROUGH; | 
					
						
							|  |  |  | 	FALSE; | 
					
						
							|  |  |  | 	FOR; | 
					
						
							|  |  |  | 	FUNC; | 
					
						
							|  |  |  | 	GO; | 
					
						
							|  |  |  | 	GOTO; | 
					
						
							|  |  |  | 	IF; | 
					
						
							|  |  |  | 	IMPORT; | 
					
						
							|  |  |  | 	INTERFACE; | 
					
						
							| 
									
										
										
										
											2008-07-08 16:39:04 -07:00
										 |  |  | 	IOTA; | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	MAP; | 
					
						
							|  |  |  | 	NEW; | 
					
						
							|  |  |  | 	NIL; | 
					
						
							|  |  |  | 	PACKAGE; | 
					
						
							|  |  |  | 	RANGE; | 
					
						
							|  |  |  | 	RETURN; | 
					
						
							|  |  |  | 	SELECT; | 
					
						
							|  |  |  | 	STRUCT; | 
					
						
							|  |  |  | 	SWITCH; | 
					
						
							|  |  |  | 	TRUE; | 
					
						
							|  |  |  | 	TYPE; | 
					
						
							|  |  |  | 	VAR; | 
					
						
							|  |  |  | 	KEYWORDS_END; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | var Keywords *map [string] int; | 
					
						
							| 
									
										
										
										
											2008-07-14 18:06:41 -07:00
										 |  |  | var VerboseMsgs bool;  // error message customization | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-04 15:37:47 -07:00
										 |  |  | export func TokenName(tok int) string { | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	switch (tok) { | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	case ILLEGAL: return "illegal"; | 
					
						
							|  |  |  | 	case EOF: return "eof"; | 
					
						
							| 
									
										
										
										
											2008-08-05 18:52:37 -07:00
										 |  |  | 	case INT: return "int"; | 
					
						
							|  |  |  | 	case FLOAT: return "float"; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	case STRING: return "string"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case COMMA: return ","; | 
					
						
							|  |  |  | 	case COLON: return ":"; | 
					
						
							|  |  |  | 	case SEMICOLON: return ";"; | 
					
						
							|  |  |  | 	case PERIOD: return "."; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case LPAREN: return "("; | 
					
						
							|  |  |  | 	case RPAREN: return ")"; | 
					
						
							|  |  |  | 	case LBRACK: return "["; | 
					
						
							|  |  |  | 	case RBRACK: return "]"; | 
					
						
							| 
									
										
										
										
											2008-07-08 16:39:04 -07:00
										 |  |  | 	case LBRACE: return "LBRACE"; | 
					
						
							|  |  |  | 	case RBRACE: return "RBRACE"; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	case ASSIGN: return "="; | 
					
						
							|  |  |  | 	case DEFINE: return ":="; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	case INC: return "++"; | 
					
						
							|  |  |  | 	case DEC: return "--"; | 
					
						
							|  |  |  | 	case NOT: return "!"; | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	case AND: return "&"; | 
					
						
							|  |  |  | 	case OR: return "|"; | 
					
						
							|  |  |  | 	case XOR: return "^"; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	case ADD: return "+"; | 
					
						
							|  |  |  | 	case SUB: return "-"; | 
					
						
							|  |  |  | 	case MUL: return "*"; | 
					
						
							|  |  |  | 	case QUO: return "/"; | 
					
						
							|  |  |  | 	case REM: return "%"; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	case EQL: return "=="; | 
					
						
							|  |  |  | 	case NEQ: return "!="; | 
					
						
							|  |  |  | 	case LSS: return "<"; | 
					
						
							|  |  |  | 	case LEQ: return "<="; | 
					
						
							|  |  |  | 	case GTR: return ">"; | 
					
						
							|  |  |  | 	case GEQ: return ">="; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case SHL: return "<<"; | 
					
						
							|  |  |  | 	case SHR: return ">>"; | 
					
						
							| 
									
										
										
										
											2008-07-16 17:00:48 -07:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-09-17 13:05:39 -07:00
										 |  |  | 	case ARROW: return "<-"; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	case ADD_ASSIGN: return "+="; | 
					
						
							|  |  |  | 	case SUB_ASSIGN: return "-="; | 
					
						
							|  |  |  | 	case MUL_ASSIGN: return "+="; | 
					
						
							|  |  |  | 	case QUO_ASSIGN: return "/="; | 
					
						
							|  |  |  | 	case REM_ASSIGN: return "%="; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case AND_ASSIGN: return "&="; | 
					
						
							|  |  |  | 	case OR_ASSIGN: return "|="; | 
					
						
							|  |  |  | 	case XOR_ASSIGN: return "^="; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case SHL_ASSIGN: return "<<="; | 
					
						
							|  |  |  | 	case SHR_ASSIGN: return ">>="; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-10 14:42:33 -07:00
										 |  |  | 	case LAND: return "&&"; | 
					
						
							|  |  |  | 	case LOR: return "||"; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-11 20:40:37 -07:00
										 |  |  | 	case IDENT: return "ident"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	case BREAK: return "break"; | 
					
						
							|  |  |  | 	case CASE: return "case"; | 
					
						
							| 
									
										
										
										
											2008-07-07 17:27:14 -07:00
										 |  |  | 	case CHAN: return "chan"; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	case CONST: return "const"; | 
					
						
							|  |  |  | 	case CONTINUE: return "continue"; | 
					
						
							|  |  |  | 	case DEFAULT: return "default"; | 
					
						
							|  |  |  | 	case ELSE: return "else"; | 
					
						
							|  |  |  | 	case EXPORT: return "export"; | 
					
						
							|  |  |  | 	case FALLTHROUGH: return "fallthrough"; | 
					
						
							|  |  |  | 	case FALSE: return "false"; | 
					
						
							|  |  |  | 	case FOR: return "for"; | 
					
						
							|  |  |  | 	case FUNC: return "func"; | 
					
						
							|  |  |  | 	case GO: return "go"; | 
					
						
							|  |  |  | 	case GOTO: return "goto"; | 
					
						
							|  |  |  | 	case IF: return "if"; | 
					
						
							|  |  |  | 	case IMPORT: return "import"; | 
					
						
							|  |  |  | 	case INTERFACE: return "interface"; | 
					
						
							| 
									
										
										
										
											2008-07-08 16:39:04 -07:00
										 |  |  | 	case IOTA: return "iota"; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	case MAP: return "map"; | 
					
						
							|  |  |  | 	case NEW: return "new"; | 
					
						
							|  |  |  | 	case NIL: return "nil"; | 
					
						
							|  |  |  | 	case PACKAGE: return "package"; | 
					
						
							|  |  |  | 	case RANGE: return "range"; | 
					
						
							|  |  |  | 	case RETURN: return "return"; | 
					
						
							|  |  |  | 	case SELECT: return "select"; | 
					
						
							|  |  |  | 	case STRUCT: return "struct"; | 
					
						
							|  |  |  | 	case SWITCH: return "switch"; | 
					
						
							|  |  |  | 	case TRUE: return "true"; | 
					
						
							|  |  |  | 	case TYPE: return "type"; | 
					
						
							|  |  |  | 	case VAR: return "var"; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	return "???"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-30 17:36:03 -07:00
										 |  |  | func init() { | 
					
						
							|  |  |  | 	Keywords = new(map [string] int); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	for i := KEYWORDS_BEG; i <= KEYWORDS_END; i++ { | 
					
						
							|  |  |  | 	  Keywords[TokenName(i)] = i; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	// Provide column information in error messages for gri only... | 
					
						
							| 
									
										
										
										
											2008-08-11 09:45:40 -07:00
										 |  |  | 	VerboseMsgs = Platform.USER == "gri"; | 
					
						
							| 
									
										
										
										
											2008-07-30 17:36:03 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func is_whitespace(ch int) bool { | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	return ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t'; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func is_letter(ch int) bool { | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 128 ; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func digit_val(ch int) int { | 
					
						
							| 
									
										
										
										
											2008-07-03 18:07:03 -07:00
										 |  |  | 	if '0' <= ch && ch <= '9' { | 
					
						
							|  |  |  | 		return ch - '0'; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if 'a' <= ch && ch <= 'f' { | 
					
						
							|  |  |  | 		return ch - 'a' + 10; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if 'A' <= ch && ch <= 'F' { | 
					
						
							|  |  |  | 		return ch - 'A' + 10; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 16;  // larger than any legal digit val | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-04 10:19:36 -07:00
										 |  |  | export type Scanner struct { | 
					
						
							| 
									
										
										
										
											2008-07-10 14:42:33 -07:00
										 |  |  | 	filename string;  // error reporting only | 
					
						
							|  |  |  | 	nerrors int;  // number of errors | 
					
						
							|  |  |  | 	errpos int;  // last error position | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 	src string;  // scanned source | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 	pos int;  // current reading position | 
					
						
							| 
									
										
										
										
											2008-07-03 18:07:03 -07:00
										 |  |  | 	ch int;  // one char look-ahead | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 	chpos int;  // position of ch | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | // Read the next Unicode char into S.ch. | 
					
						
							|  |  |  | // S.ch < 0 means end-of-file. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func (S *Scanner) Next() { | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	const ( | 
					
						
							|  |  |  | 		Bit1 = 7; | 
					
						
							|  |  |  | 		Bitx = 6; | 
					
						
							|  |  |  | 		Bit2 = 5; | 
					
						
							|  |  |  | 		Bit3 = 4; | 
					
						
							|  |  |  | 		Bit4 = 3; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-11 18:44:41 -07:00
										 |  |  | 		T1 = (1 << (Bit1 + 1) - 1) ^ 0xFF;  // 0000 0000 | 
					
						
							|  |  |  | 		Tx = (1 << (Bitx + 1) - 1) ^ 0xFF;  // 1000 0000 | 
					
						
							|  |  |  | 		T2 = (1 << (Bit2 + 1) - 1) ^ 0xFF;  // 1100 0000 | 
					
						
							|  |  |  | 		T3 = (1 << (Bit3 + 1) - 1) ^ 0xFF;  // 1110 0000 | 
					
						
							|  |  |  | 		T4 = (1 << (Bit4 + 1) - 1) ^ 0xFF;  // 1111 0000 | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		Rune1 = 1 << (Bit1 + 0*Bitx) - 1;  // 0000 0000 0111 1111 | 
					
						
							|  |  |  | 		Rune2 = 1 << (Bit2 + 1*Bitx) - 1;  // 0000 0111 1111 1111 | 
					
						
							|  |  |  | 		Rune3 = 1 << (Bit3 + 2*Bitx) - 1;  // 1111 1111 1111 1111 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Maskx = 0x3F;  // 1 << Bitx - 1;  // 0011 1111 | 
					
						
							|  |  |  | 		Testx = 0xC0;  // Maskx ^ 0xFF;  // 1100 0000 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Bad	= 0xFFFD;  // Runeerror | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-11 09:45:40 -07:00
										 |  |  | 	src := S.src; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	lim := len(src); | 
					
						
							|  |  |  | 	pos := S.pos; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	// 1-byte sequence | 
					
						
							|  |  |  | 	// 0000-007F => T1 | 
					
						
							|  |  |  | 	if pos >= lim { | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		S.ch = -1;  // end of file | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 		S.chpos = lim; | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	c0 := int(src[pos]); | 
					
						
							|  |  |  | 	pos++; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	if c0 < Tx { | 
					
						
							|  |  |  | 		S.ch = c0; | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 		S.chpos = S.pos; | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		S.pos = pos; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 2-byte sequence | 
					
						
							|  |  |  | 	// 0080-07FF => T2 Tx | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	if pos >= lim { | 
					
						
							|  |  |  | 		goto bad; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	c1 := int(src[pos]) ^ Tx; | 
					
						
							|  |  |  | 	pos++; | 
					
						
							|  |  |  | 	if c1 & Testx != 0 { | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 		goto bad; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if c0 < T3 { | 
					
						
							|  |  |  | 		if c0 < T2 { | 
					
						
							|  |  |  | 			goto bad; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 		r := (c0 << Bitx | c1) & Rune2; | 
					
						
							|  |  |  | 		if  r <= Rune1 { | 
					
						
							|  |  |  | 			goto bad; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		S.ch = r; | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 		S.chpos = S.pos; | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		S.pos = pos; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	// 3-byte sequence | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	// 0800-FFFF => T3 Tx Tx | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	if pos >= lim { | 
					
						
							|  |  |  | 		goto bad; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	c2 := int(src[pos]) ^ Tx; | 
					
						
							|  |  |  | 	pos++; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	if c2 & Testx != 0 { | 
					
						
							|  |  |  | 		goto bad; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if c0 < T4 { | 
					
						
							|  |  |  | 		r := (((c0 << Bitx | c1) << Bitx) | c2) & Rune3; | 
					
						
							|  |  |  | 		if r <= Rune2 { | 
					
						
							|  |  |  | 			goto bad; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		S.ch = r; | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 		S.chpos = S.pos; | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		S.pos = pos; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// bad encoding | 
					
						
							|  |  |  | bad: | 
					
						
							|  |  |  | 	S.ch = Bad; | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 	S.chpos = S.pos; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	S.pos += 1; | 
					
						
							|  |  |  | 	return; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-09 16:23:48 -07:00
										 |  |  | // Compute (line, column) information for a given source position. | 
					
						
							|  |  |  | func (S *Scanner) LineCol(pos int) (line, col int) { | 
					
						
							|  |  |  | 	line = 1; | 
					
						
							|  |  |  | 	lpos := 0; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	src := S.src; | 
					
						
							|  |  |  | 	if pos > len(src) { | 
					
						
							|  |  |  | 		pos = len(src); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i := 0; i < pos; i++ { | 
					
						
							| 
									
										
										
										
											2008-07-09 17:08:20 -07:00
										 |  |  | 		if src[i] == '\n' { | 
					
						
							| 
									
										
										
										
											2008-07-09 16:23:48 -07:00
										 |  |  | 			line++; | 
					
						
							|  |  |  | 			lpos = i; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	return line, pos - lpos; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (S *Scanner) Error(pos int, msg string) { | 
					
						
							| 
									
										
										
										
											2008-07-10 14:42:33 -07:00
										 |  |  | 	const errdist = 10; | 
					
						
							| 
									
										
										
										
											2008-07-17 18:02:10 -07:00
										 |  |  | 	delta := pos - S.errpos;  // may be negative! | 
					
						
							| 
									
										
										
										
											2008-07-30 17:36:03 -07:00
										 |  |  | 	if delta < 0 { | 
					
						
							|  |  |  | 		delta = -delta; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if delta > errdist || S.nerrors == 0 /* always report first error */ { | 
					
						
							| 
									
										
										
										
											2008-08-11 21:20:42 -07:00
										 |  |  | 		print(S.filename); | 
					
						
							| 
									
										
										
										
											2008-07-30 17:36:03 -07:00
										 |  |  | 		if pos >= 0 { | 
					
						
							|  |  |  | 			// print position | 
					
						
							|  |  |  | 			line, col := S.LineCol(pos); | 
					
						
							|  |  |  | 			if VerboseMsgs { | 
					
						
							| 
									
										
										
										
											2008-08-11 21:20:42 -07:00
										 |  |  | 				print(":", line, ":", col); | 
					
						
							| 
									
										
										
										
											2008-07-30 17:36:03 -07:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2008-08-11 21:20:42 -07:00
										 |  |  | 				print(":", line); | 
					
						
							| 
									
										
										
										
											2008-07-30 17:36:03 -07:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-07-14 18:06:41 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-08-11 21:20:42 -07:00
										 |  |  | 		print(": ", msg, "\n"); | 
					
						
							| 
									
										
										
										
											2008-07-10 14:42:33 -07:00
										 |  |  | 		S.nerrors++; | 
					
						
							|  |  |  | 		S.errpos = pos; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-07-17 15:11:46 -07:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	if S.nerrors >= 10 { | 
					
						
							|  |  |  | 		sys.exit(1); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-07-09 16:23:48 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func (S *Scanner) Open(filename, src string) { | 
					
						
							| 
									
										
										
										
											2008-07-10 14:42:33 -07:00
										 |  |  | 	S.filename = filename; | 
					
						
							|  |  |  | 	S.nerrors = 0; | 
					
						
							|  |  |  | 	S.errpos = 0; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	S.src = src; | 
					
						
							|  |  |  | 	S.pos = 0; | 
					
						
							|  |  |  | 	S.Next(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | func CharString(ch int) string { | 
					
						
							|  |  |  | 	s := string(ch); | 
					
						
							|  |  |  | 	switch ch { | 
					
						
							| 
									
										
										
										
											2008-07-10 14:42:33 -07:00
										 |  |  | 	case '\a': s = `\a`; | 
					
						
							|  |  |  | 	case '\b': s = `\b`; | 
					
						
							|  |  |  | 	case '\f': s = `\f`; | 
					
						
							|  |  |  | 	case '\n': s = `\n`; | 
					
						
							|  |  |  | 	case '\r': s = `\r`; | 
					
						
							|  |  |  | 	case '\t': s = `\t`; | 
					
						
							|  |  |  | 	case '\v': s = `\v`; | 
					
						
							|  |  |  | 	case '\\': s = `\\`; | 
					
						
							|  |  |  | 	case '\'': s = `\'`; | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-08-11 09:45:40 -07:00
										 |  |  | 	return "'" + s + "' (U+" + Utils.IntToString(ch, 16) + ")"; | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func (S *Scanner) Expect(ch int) { | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	if S.ch != ch { | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 		S.Error(S.chpos, "expected " + CharString(ch) + ", found " + CharString(S.ch)); | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-07-09 16:23:48 -07:00
										 |  |  | 	S.Next();  // make always progress | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func (S *Scanner) SkipWhitespace() { | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	for is_whitespace(S.ch) { | 
					
						
							|  |  |  | 		S.Next(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func (S *Scanner) SkipComment() { | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 	// '/' already consumed | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	if S.ch == '/' { | 
					
						
							|  |  |  | 		// comment | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		S.Next(); | 
					
						
							|  |  |  | 		for S.ch != '\n' && S.ch >= 0 { | 
					
						
							|  |  |  | 			S.Next(); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 		 | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		/* comment */ | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 		pos := S.chpos - 1; | 
					
						
							|  |  |  | 		S.Expect('*'); | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		for S.ch >= 0 { | 
					
						
							|  |  |  | 			ch := S.ch; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 			S.Next(); | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 			if ch == '*' && S.ch == '/' { | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 				S.Next(); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-07-09 16:23:48 -07:00
										 |  |  | 		S.Error(pos, "comment not terminated"); | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func (S *Scanner) ScanIdentifier() (tok int, val string) { | 
					
						
							|  |  |  | 	pos := S.chpos; | 
					
						
							| 
									
										
										
										
											2008-07-03 18:07:03 -07:00
										 |  |  | 	for is_letter(S.ch) || digit_val(S.ch) < 10 { | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 		S.Next(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 	val = S.src[pos : S.chpos]; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	var present bool; | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 	tok, present = Keywords[val]; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	if !present { | 
					
						
							|  |  |  | 		tok = IDENT; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 	return tok, val; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func (S *Scanner) ScanMantissa(base int) { | 
					
						
							| 
									
										
										
										
											2008-07-03 18:07:03 -07:00
										 |  |  | 	for digit_val(S.ch) < base { | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 		S.Next(); | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-05 18:52:37 -07:00
										 |  |  | func (S *Scanner) ScanNumber(seen_decimal_point bool) (tok int, val string) { | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 	pos := S.chpos; | 
					
						
							| 
									
										
										
										
											2008-08-05 18:52:37 -07:00
										 |  |  | 	tok = INT; | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	if seen_decimal_point { | 
					
						
							| 
									
										
										
										
											2008-08-05 18:52:37 -07:00
										 |  |  | 		tok = FLOAT; | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 		pos--;  // '.' is one byte | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		S.ScanMantissa(10); | 
					
						
							|  |  |  | 		goto exponent; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if S.ch == '0' { | 
					
						
							| 
									
										
										
										
											2008-07-09 10:16:33 -07:00
										 |  |  | 		// int or float | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		S.Next(); | 
					
						
							|  |  |  | 		if S.ch == 'x' || S.ch == 'X' { | 
					
						
							|  |  |  | 			// hexadecimal int | 
					
						
							|  |  |  | 			S.Next(); | 
					
						
							|  |  |  | 			S.ScanMantissa(16); | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2008-07-09 10:16:33 -07:00
										 |  |  | 			// octal int or float | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 			S.ScanMantissa(8); | 
					
						
							| 
									
										
										
										
											2008-07-09 10:16:33 -07:00
										 |  |  | 			if digit_val(S.ch) < 10 || S.ch == '.' || S.ch == 'e' || S.ch == 'E' { | 
					
						
							|  |  |  | 				// float | 
					
						
							| 
									
										
										
										
											2008-08-05 18:52:37 -07:00
										 |  |  | 				tok = FLOAT; | 
					
						
							| 
									
										
										
										
											2008-07-09 10:16:33 -07:00
										 |  |  | 				goto mantissa; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// octal int | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 		goto exit; | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-09 10:16:33 -07:00
										 |  |  | mantissa: | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	// decimal int or float | 
					
						
							|  |  |  | 	S.ScanMantissa(10); | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 	if S.ch == '.' { | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		// float | 
					
						
							| 
									
										
										
										
											2008-08-05 18:52:37 -07:00
										 |  |  | 		tok = FLOAT; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 		S.Next(); | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		S.ScanMantissa(10) | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	 | 
					
						
							|  |  |  | exponent: | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 	if S.ch == 'e' || S.ch == 'E' { | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		// float | 
					
						
							| 
									
										
										
										
											2008-08-05 18:52:37 -07:00
										 |  |  | 		tok = FLOAT; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 		S.Next(); | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 		if S.ch == '-' || S.ch == '+' { | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 			S.Next(); | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		S.ScanMantissa(10); | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 	 | 
					
						
							|  |  |  | exit: | 
					
						
							| 
									
										
										
										
											2008-08-05 18:52:37 -07:00
										 |  |  | 	return tok, S.src[pos : S.chpos]; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-03 18:07:03 -07:00
										 |  |  | func (S *Scanner) ScanDigits(n int, base int) { | 
					
						
							|  |  |  | 	for digit_val(S.ch) < base { | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 		S.Next(); | 
					
						
							| 
									
										
										
										
											2008-07-03 18:07:03 -07:00
										 |  |  | 		n--; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-07-03 18:07:03 -07:00
										 |  |  | 	if n > 0 { | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 		S.Error(S.chpos, "illegal char escape"); | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func (S *Scanner) ScanEscape() string { | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	// TODO: fix this routine | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	ch := S.ch; | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 	pos := S.chpos; | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	S.Next(); | 
					
						
							|  |  |  | 	switch (ch) { | 
					
						
							|  |  |  | 	case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '\'', '"': | 
					
						
							|  |  |  | 		return string(ch); | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 		 | 
					
						
							|  |  |  | 	case '0', '1', '2', '3', '4', '5', '6', '7': | 
					
						
							| 
									
										
										
										
											2008-07-03 18:07:03 -07:00
										 |  |  | 		S.ScanDigits(3 - 1, 8);  // 1 char already read | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		return "";  // TODO fix this | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 		 | 
					
						
							|  |  |  | 	case 'x': | 
					
						
							| 
									
										
										
										
											2008-07-03 18:07:03 -07:00
										 |  |  | 		S.ScanDigits(2, 16); | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		return "";  // TODO fix this | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 		 | 
					
						
							|  |  |  | 	case 'u': | 
					
						
							| 
									
										
										
										
											2008-07-03 18:07:03 -07:00
										 |  |  | 		S.ScanDigits(4, 16); | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		return "";  // TODO fix this | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	case 'U': | 
					
						
							| 
									
										
										
										
											2008-07-03 18:07:03 -07:00
										 |  |  | 		S.ScanDigits(8, 16); | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		return "";  // TODO fix this | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 		S.Error(pos, "illegal char escape"); | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-09-11 15:38:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return "";  // TODO fix this | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func (S *Scanner) ScanChar() string { | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	// '\'' already consumed | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 	pos := S.chpos - 1; | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	ch := S.ch; | 
					
						
							|  |  |  | 	S.Next(); | 
					
						
							|  |  |  | 	if ch == '\\' { | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 		S.ScanEscape(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-03 18:07:03 -07:00
										 |  |  | 	S.Expect('\''); | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 	return S.src[pos : S.chpos]; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func (S *Scanner) ScanString() string { | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	// '"' already consumed | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 	pos := S.chpos - 1; | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	for S.ch != '"' { | 
					
						
							|  |  |  | 		ch := S.ch; | 
					
						
							|  |  |  | 		S.Next(); | 
					
						
							|  |  |  | 		if ch == '\n' || ch < 0 { | 
					
						
							| 
									
										
										
										
											2008-07-09 16:23:48 -07:00
										 |  |  | 			S.Error(pos, "string not terminated"); | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 		if ch == '\\' { | 
					
						
							|  |  |  | 			S.ScanEscape(); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	S.Next(); | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 	return S.src[pos : S.chpos]; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func (S *Scanner) ScanRawString() string { | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	// '`' already consumed | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 	pos := S.chpos - 1; | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 	for S.ch != '`' { | 
					
						
							|  |  |  | 		ch := S.ch; | 
					
						
							|  |  |  | 		S.Next(); | 
					
						
							|  |  |  | 		if ch == '\n' || ch < 0 { | 
					
						
							| 
									
										
										
										
											2008-07-09 16:23:48 -07:00
										 |  |  | 			S.Error(pos, "string not terminated"); | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-07-03 16:51:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	S.Next(); | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 	return S.src[pos : S.chpos]; | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func (S *Scanner) Select2(tok0, tok1 int) int { | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 	if S.ch == '=' { | 
					
						
							|  |  |  | 		S.Next(); | 
					
						
							|  |  |  | 		return tok1; | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return tok0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func (S *Scanner) Select3(tok0, tok1, ch2, tok2 int) int { | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 	if S.ch == '=' { | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 		S.Next(); | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 		return tok1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if S.ch == ch2 { | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 		S.Next(); | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 		return tok2; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return tok0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func (S *Scanner) Select4(tok0, tok1, ch2, tok2, tok3 int) int { | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 	if S.ch == '=' { | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 		S.Next(); | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 		return tok1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if S.ch == ch2 { | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 		S.Next(); | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 		if S.ch == '=' { | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 			S.Next(); | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 			return tok3; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return tok2; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return tok0; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | func (S *Scanner) Scan() (tok, pos int, val string) { | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 	S.SkipWhitespace(); | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-03 18:07:03 -07:00
										 |  |  | 	ch := S.ch; | 
					
						
							| 
									
										
										
										
											2008-07-10 14:42:33 -07:00
										 |  |  | 	tok = ILLEGAL; | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 	pos = S.chpos; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-03 18:07:03 -07:00
										 |  |  | 	switch { | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 	case is_letter(ch): tok, val = S.ScanIdentifier(); | 
					
						
							| 
									
										
										
										
											2008-08-05 18:52:37 -07:00
										 |  |  | 	case digit_val(ch) < 10: tok, val = S.ScanNumber(false); | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2008-07-10 13:45:02 -07:00
										 |  |  | 		S.Next();  // always make progress | 
					
						
							| 
									
										
										
										
											2008-07-02 23:19:31 -07:00
										 |  |  | 		switch ch { | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 		case -1: tok = EOF; | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 		case '"': tok, val = STRING, S.ScanString(); | 
					
						
							| 
									
										
										
										
											2008-08-05 18:52:37 -07:00
										 |  |  | 		case '\'': tok, val = INT, S.ScanChar(); | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 		case '`': tok, val = STRING, S.ScanRawString(); | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 		case ':': tok = S.Select2(COLON, DEFINE); | 
					
						
							|  |  |  | 		case '.': | 
					
						
							| 
									
										
										
										
											2008-07-03 18:07:03 -07:00
										 |  |  | 			if digit_val(S.ch) < 10 { | 
					
						
							| 
									
										
										
										
											2008-08-05 18:52:37 -07:00
										 |  |  | 				tok, val = S.ScanNumber(true); | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				tok = PERIOD; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case ',': tok = COMMA; | 
					
						
							|  |  |  | 		case ';': tok = SEMICOLON; | 
					
						
							|  |  |  | 		case '(': tok = LPAREN; | 
					
						
							|  |  |  | 		case ')': tok = RPAREN; | 
					
						
							|  |  |  | 		case '[': tok = LBRACK; | 
					
						
							|  |  |  | 		case ']': tok = RBRACK; | 
					
						
							|  |  |  | 		case '{': tok = LBRACE; | 
					
						
							|  |  |  | 		case '}': tok = RBRACE; | 
					
						
							|  |  |  | 		case '+': tok = S.Select3(ADD, ADD_ASSIGN, '+', INC); | 
					
						
							| 
									
										
										
										
											2008-09-17 13:05:39 -07:00
										 |  |  | 		case '-': tok = S.Select3(SUB, SUB_ASSIGN, '-', DEC); | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 		case '*': tok = S.Select2(MUL, MUL_ASSIGN); | 
					
						
							|  |  |  | 		case '/': | 
					
						
							|  |  |  | 			if S.ch == '/' || S.ch == '*' { | 
					
						
							|  |  |  | 				S.SkipComment(); | 
					
						
							|  |  |  | 				// cannot simply return because of 6g bug | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 				tok, pos, val = S.Scan(); | 
					
						
							|  |  |  | 				return tok, pos, val; | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			tok = S.Select2(QUO, QUO_ASSIGN); | 
					
						
							|  |  |  | 		case '%': tok = S.Select2(REM, REM_ASSIGN); | 
					
						
							|  |  |  | 		case '^': tok = S.Select2(XOR, XOR_ASSIGN); | 
					
						
							| 
									
										
										
										
											2008-07-16 17:00:48 -07:00
										 |  |  | 		case '<': | 
					
						
							|  |  |  | 			if S.ch == '-' { | 
					
						
							|  |  |  | 				S.Next(); | 
					
						
							| 
									
										
										
										
											2008-09-17 13:05:39 -07:00
										 |  |  | 				tok = ARROW; | 
					
						
							| 
									
										
										
										
											2008-07-16 17:00:48 -07:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				tok = S.Select4(LSS, LEQ, '<', SHL, SHL_ASSIGN); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-07-03 15:16:51 -07:00
										 |  |  | 		case '>': tok = S.Select4(GTR, GEQ, '>', SHR, SHR_ASSIGN); | 
					
						
							|  |  |  | 		case '=': tok = S.Select2(ASSIGN, EQL); | 
					
						
							|  |  |  | 		case '!': tok = S.Select2(NOT, NEQ); | 
					
						
							| 
									
										
										
										
											2008-07-10 14:42:33 -07:00
										 |  |  | 		case '&': tok = S.Select3(AND, AND_ASSIGN, '&', LAND); | 
					
						
							|  |  |  | 		case '|': tok = S.Select3(OR, OR_ASSIGN, '|', LOR); | 
					
						
							|  |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 			S.Error(pos, "illegal character " + CharString(ch)); | 
					
						
							| 
									
										
										
										
											2008-07-10 14:42:33 -07:00
										 |  |  | 			tok = ILLEGAL; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:18:29 -07:00
										 |  |  | 	return tok, pos, val; | 
					
						
							| 
									
										
										
										
											2008-07-02 17:02:55 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2008-08-06 18:57:37 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export type Token struct { | 
					
						
							|  |  |  | 	pos int; | 
					
						
							|  |  |  | 	tok int; | 
					
						
							|  |  |  | 	val string; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (S *Scanner) Server(c *chan *Token) { | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		t := new(Token); | 
					
						
							|  |  |  | 		t.tok, t.pos, t.val = S.Scan(); | 
					
						
							| 
									
										
										
										
											2008-09-17 13:05:39 -07:00
										 |  |  | 		c <- t; | 
					
						
							| 
									
										
										
										
											2008-08-06 18:57:37 -07:00
										 |  |  | 		if t.tok == EOF { | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |