src/lexer.cc

changeset 82
841562f5a32f
parent 81
071715c17296
child 85
264a61e9eba0
--- a/src/lexer.cc	Sat Jan 18 02:11:45 2014 +0200
+++ b/src/lexer.cc	Sun Jan 19 20:16:00 2014 +0200
@@ -34,25 +34,33 @@
 static string_list	g_file_name_stack;
 static lexer*		g_main_lexer = null;
 
+// =============================================================================
+//
 lexer::lexer()
 {
 	assert (g_main_lexer == null);
 	g_main_lexer = this;
 }
 
+// =============================================================================
+//
 lexer::~lexer()
 {
 	g_main_lexer = null;
 }
 
+// =============================================================================
+//
 void lexer::process_file (string file_name)
 {
+	g_file_name_stack << file_name;
 	FILE* fp = fopen (file_name, "r");
 
 	if (fp == null)
 		error ("couldn't open %1 for reading: %2", file_name, strerror (errno));
 
 	lexer_scanner sc (fp);
+	check_file_header (sc);
 
 	while (sc.get_next_token())
 	{
@@ -82,13 +90,58 @@
 			tok.column = sc.get_column();
 			tok.type = sc.get_token_type();
 			tok.text = sc.get_token_text();
-			//	devf ("Token #%1: %2:%3:%4: %5 (%6)\n", m_tokens.size(),
-			//		tok.file, tok.line, tok.column, describe_token (&tok), describe_token_type (tok.type));
+
+			// devf ("Token #%1: %2:%3:%4: %5 (%6)\n", m_tokens.size(),
+			//	tok.file, tok.line, tok.column, describe_token (&tok), describe_token_type (tok.type));
+
 			m_tokens << tok;
 		}
 	}
 
 	m_token_position = m_tokens.begin() - 1;
+	g_file_name_stack.remove (file_name);
+}
+
+// ============================================================================
+//
+static bool is_valid_header (string header)
+{
+	if (header.ends_with ("\n"))
+		header.remove_from_end (1);
+
+	string_list tokens = header.split (" ");
+
+	if (tokens.size() != 2 || tokens[0] != "#!botc" || tokens[1].empty())
+		return false;
+
+	string_list nums = tokens[1].split (".");
+
+	if (nums.size() == 2)
+		nums << "0";
+	elif (nums.size() != 3)
+		return false;
+
+	bool ok_a, ok_b, ok_c;
+	long major = nums[0].to_long (&ok_a);
+	long minor = nums[1].to_long (&ok_b);
+	long patch = nums[2].to_long (&ok_c);
+
+	if (!ok_a || !ok_b || !ok_c)
+		return false;
+
+	if (VERSION_NUMBER < MAKE_VERSION_NUMBER (major, minor, patch))
+		error ("The script file requires " APPNAME " v%1, this is v%2",
+			make_version_string (major, minor, patch), get_version_string (e_short_form));
+
+	return true;
+}
+
+// ============================================================================
+//
+void lexer::check_file_header (lexer_scanner& sc)
+{
+	if (!is_valid_header (sc.read_line()))
+		error ("Not a valid botscript file! File must start with '#!botc <version>'");
 }
 
 // =============================================================================
@@ -125,14 +178,23 @@
 // =============================================================================
 // eugh..
 //
-void lexer::must_get_next_from_scanner (lexer_scanner& sc, e_token tok)
+void lexer::must_get_next_from_scanner (lexer_scanner& sc, e_token tt)
 {
 	if (!sc.get_next_token())
 		error ("unexpected EOF");
 
-	if (tok != tk_any && sc.get_token_type() != tok)
-		error ("expected %1, got %2", describe_token_type (tok),
-			   describe_token (get_token()));
+	if (tt != tk_any && sc.get_token_type() != tt)
+	{	// TODO
+		token tok;
+		tok.type = sc.get_token_type();
+		tok.text = sc.get_token_text();
+
+		error ("at %1:%2: expected %3, got %4",
+			g_file_name_stack.last(),
+			sc.get_line(),
+			describe_token_type (tt),
+			describe_token (&tok));
+	}
 }
 
 // =============================================================================
@@ -199,20 +261,11 @@
 
 	switch (tok_type)
 	{
-		case tk_symbol:
-			return tok ? tok->text : "a symbol";
-
-		case tk_number:
-			return tok ? tok->text : "a number";
-
-		case tk_string:
-			return tok ? ("\"" + tok->text + "\"") : "a string";
-
-		case tk_any:
-			return tok ? tok->text : "any token";
-
-		default:
-			break;
+		case tk_symbol:	return tok ? tok->text : "a symbol";
+		case tk_number:	return tok ? tok->text : "a number";
+		case tk_string:	return tok ? ("\"" + tok->text + "\"") : "a string";
+		case tk_any:	return tok ? tok->text : "any token";
+		default: break;
 	}
 
 	return "";

mercurial