Jump to content

Help please! no viable alternative at input


irswat

Recommended Posts

Had this text file parser almost working. Reworked the logic and optimized some of the code and now I'm stuck on this stupid error. Here is the code:

 

function Main()
	;declarations
	string CurrentDump
	string CurrentLine
	string CurrentWord
	
	int DumpLineCount=0
	int LoopCounter=1
	int CurrentWordIndex
	int WordsOnCurrentLine=0
	int CurrentDumpWordIndex=0
	
	;implement "mic" button
	debug.trace("Initializing SVE_DumpArray")
	string[] SVE_DumpArray=new string[90]
	
	CurrentDump=Dump_PO()
	debug.trace("Printing SVE_PO" + CurrentDump)
	DumpLineCount=GetNumLines(CurrentDump)
	debug.trace("SVE_PO number of lines: " + DumpLineCount)
	
	while (LoopCounter<=DumpLineCount)
		CurrentLine=GetLine(CurrentDump, LoopCounter, DumpLineCount)
		debug.trace("Current Line: " + CurrentLine)
		
		WordsOnCurrentLine=GetNumWords(CurrentLine)
		debug.trace("Number of words on current line: " + WordsOnCurrentLine)
		
		CurrentWordIndex=1
		while (CurrentWordIndex<=WordsOnCurrentLine)
			;Get word y on line x
			;define CurrentDumpWordIndex
			CurrentWord=GetWord(CurrentLine, LoopCounter, CurrentWordIndex)
			;store word y in array
			SVE_DumpArray[CurrentDumpWordIndex]=CurrentWord
			CurrentWordIndex+=1
			CurrentDumpWordIndex+=1
		endWhile
				
		LoopCounter+=1
		
	endWhile 
	
endfunction

string function Dump_PO()
	;shoutout to MinionMaster for helping me understand the syntax and Find the right functions in MiscUtil.psc
	;this function is his work
	string SVE_PO
	string sDatafileName = "data/SVE_PI.txt"
	
	int LineCountParserIndex=0
	int EndOfFileFound=0
	
	debug.trace("dumping from " + sDatafileName + "to SVE_PO")

	if MiscUtil.FileExists(sDatafileName)
		debug.trace("File found: reading file.")
		SVE_PO = MiscUtil.ReadFromFile (sDatafileName)
		EndOfFileFound=Find(SVE_PO, "/delete", LineCountParserIndex)
		if EndOfFileFound==-1
			MiscUtil.WriteToFile(sDatafileName, "/delete", true, false)
		endif
	endif
	
	return SVE_PO
endfunction

int function GetNumLines(string SVE_PO)

	;Find out how many distinct lines are in the string
	int LineCountParserIndex=0
	int NullCharIndex=0
	int LineCount=0
	int SVE_PO_End=-1
		
	while (SVE_PO_End==-1) ;delete not found on this line
		
		NullCharIndex=Find(SVE_PO, "/n", LineCountParserIndex) ;end of line
		
		if NullCharIndex==-1
			SVE_PO_End=Find(SVE_PO,"/delete",LineCountParserIndex) ;end of dump file
		endif
		
		LineCount=LineCount+1
		LineCountParserIndex=NullCharIndex+3
		
	endWhile	
	
	return LineCount
	
endFunction

string function GetLine(string SVE_PO,int LineNumber,int NumberOfLines)
	int NullCharIndex=0
	int LineStartIndex=0
	int EndDumpIndex
	int LinesToSkip
	int LinesSkipped
	
	string LineReturn
	
	if((LineNumber > 1) && (LineNumber < NumberOfLines))
		LinesToSkip=LineNumber-1
		LinesSkipped=0
		
		while(LinesSkipped<=LinesToSkip)
			NullCharIndex=Find(SVE_PO, "/n", LineStartIndex)
			LineStartIndex=NullCharIndex+1
			LinesSkipped+=1
		endwhile
	elseif ((LineNumber>1) && (LineNumber==NumberofLines))
		LinesToSkip=LineNumber-1
		LinesSkipped=0
		
		while(LinesSkipped<=LinesToSkip)
			EndDumpIndex=Find(SVE_PO, "/Delete", LineStartIndex)
			LineReturn=Substring(SVE_PO, LineStartIndex, EndDumpIndex)
			LinesSkipped+=1
		endwhile	
	endif
	
	NullCharIndex=Find(SVE_PO, "/n", LineStartIndex)
	if(NullCharIndex > -1) ;"/n" found on line
		LineReturn=Substring(SVE_PO, LineStartIndex, NullCharIndex)
	elseif (NullCharIndex==-1)
		EndDumpIndex=Find(SVE_PO, "/delete", LineStartIndex)
		if (EndDumpIndex>-1)	;"/delete found"
			LineReturn=Substring(SVE_PO, LineStartIndex, EndDumpIndex)
		endif
	endif
	
	return LineReturn
endFunction

 



relevant code is in the last function GetLine. "LinesToSkip=LineNumber-1"

Edited by irswat
Link to comment
Share on other sites

I comment out these two lines in two places in the function GetLine and the script compiles. It makes no sense to me.

 

no viable alternative at input 'CurrentLineNumber'
;LinesToSkip=CurrentLineNumber-1
;LinesSkipped=0
Edited by irswat
Link to comment
Share on other sites

LinesToSkip=CurrentLineNumber-1

I'm using this variable in other parts of the same function with no errors. But subtracting 1 from CurrentLineNumber is causing the compiler to throw an error. Shoutout to whoever helps me figure this one out.

Link to comment
Share on other sites

After a bit of testing it looks like the lexical analysis part of the compiler has a bug. It seems like it is having trouble telling the difference between a unary minus and a binary minus. It should be generating the following tokens:

Identifier: LinesToSkip
Binary operator: assignment
Identifier: LineNumber
Binary operator: subtraction
Integer literal: 1

but it is probably generating the following:

Identifier: LinesToSkip
Binary operator: assignment
Identifier: LineNumber
Integer literal: -1

Solution: Add a space between the subtraction operator and the integer literal so that this:

LinesToSkip=LineNumber-1

becomes this:

LinesToSkip=LineNumber- 1

I don't think I have noticed that bug before (or maybe I had just forgotten about it already) since I tend to put one space on both sides of an operator.

LinesToSkip = LineNumber - 1
Edited by mrpwn
Link to comment
Share on other sites

The explanation that I provided is based on prior experience with writing a linter, which is a piece of software that checks the validity of source code just like a compiler would do in its front end, for Papyrus. I don't have any way of proving that what I said is actually happening since I do not have access to the source code of Bethesda's compiler, but it seems like the most likely scenario to me. The linter is a part of the SublimePapyrus (GitHub repository, Nexus page) package, which I am the primary developer and maintainer of, for Sublime Text 2 and 3. The package has other neat features as well for anyone doing a lot of scripting.

 

As for how I figured it out; at first I could not see what the problem was with your script. I then copied the script into Sublime Text 3 with the SublimePapyrus package installed and let the linter have a look at the script. No errors found, but I have in the past forgotten to implement certain checks, and sometimes I have even managed to avoid bugs, found in Bethesda's compiler. At that point I figured I might need to fix something in my linter. Then I tried compiling the script with the compiler provided by Bethesda and got the same errors that you reported on the lines that you mentioned. Based on a hunch I tried messing with the whitespace between the variable names, operators, and integer literal in the lines that were causing compilation errors. No more errors when compiling with the minus and 1 characters separated by whitespace.

 

It looks like the front end of Bethesda's compiler is based on a parser generated with ANTLR based on the names of certain files found in the same folder as the compiler. I cannot say for sure if the issue you brought up is a bug with ANTLR or just this one particular compiler. I was initially looking into the possibility of using ANTLR myself when I first started writing my own linter as it was my first time writing such a program, but I ended up not going that route.

 

Edit: A bit more detail on my reasoning, if you or anyone else is interested. Lexical analysis deals with what could be considered words (names of variables, names of functions, operators, etc.). This analysis is done by grouping individual characters and generating what are often called tokens. These tokens include additional information such as the row/line number, column number of the first character in the group of characters, type of group (identifier, operator, literal, etc.). Grouping characters can sometimes be tricky as it is context-sensitive and implementation-sensitive. Consider the following two statements:

a = 2 - 1
b = -1 + 2

Those two lines assign the same value to two different variables once evaluated. However, they produce different token streams and as a result different parse trees. The first line would produce (in a simplified form):

Identifier: a
Binary operator: assignment
Integer literal: 2
Binary operator: subtraction
Integeral literal: 1

If we did not have any whitespace between - and 1, then we could produce:

Identifier: a
Binary operator: assignment
Integer literal: 2
Unary operator: negation
Integeral literal: 1

or

Identifier: a
Binary operator: assignment
Integer literal: 2
Integeral literal: -1

but given the context (an integer literal prior to a unary operator or another integer literal) we can figure out that the two integer literals are separated by a binary operator (subtraction).

 

The second line would produce either:

Identifier: b
Binary operator: assignment
Unary operator: negation
Integer literal: 1
Binary operator: addition
Integer literal: 2

or

Identifier: b
Binary operator: assignment
Integer literal: -1
Binary operator: addition
Integer literal: 2

depending on the implementation.

 

Here are some hastily drawn representations of the parse trees and how they would be evaluated (going from the parse tree at the top to the parse tree at the bottom).

Edited by mrpwn
Link to comment
Share on other sites

You're welcome.

 

You can compile scripts from within Sublime Text, though it still needs Bethesda's compiler (or a 3rd party compiler) to do so. The settings file of the SublimePapyrus package also allows you to use some of the more advanced features (e.g. multiple import folders), which cannot be used from within CK, that Bethesda's compiler is capable of. You'll still need CK to attach scripts, fill properties, and generate script fragments in quests and dialogue. Outside of those things I think you can do everything else from an external editor such as Sublime Text.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...