1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-08-02 09:29:35 +00:00

Added missing line number to error when encountering symbol that has already been declared.

This commit is contained in:
jespergravgaard 2019-03-10 09:29:02 +01:00
parent 241f8bec4d
commit 3090fe4849
9 changed files with 69 additions and 28 deletions

View File

@ -479,17 +479,17 @@ class AsmFragmentTemplateSynthesisRule {
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)vw(.)c1(.*)", null, null , "$1vd$2c1$3", null, null)); synths.add(new AsmFragmentTemplateSynthesisRule("(.*)vw(.)c1(.*)", null, null , "$1vd$2c1$3", null, null));
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)vw(.)c2(.*)", null, null , "$1vd$2c2$3", null, null)); synths.add(new AsmFragmentTemplateSynthesisRule("(.*)vw(.)c2(.*)", null, null , "$1vd$2c2$3", null, null));
/* Removed pending optimization! /* Removed awaiting optimization
// Rewrite constant unsigned word values to constant signed dword values // Rewrite constant unsigned word values to constant signed dword values
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)vwuc1(.*)", null, null , "$1vdsc1$2", null, null)); synths.add(new AsmFragmentTemplateSynthesisRule("(.*)vwuc1(.*)", null, null , "$1vdsc1$2", null, null));
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)vwuc2(.*)", null, null , "$1vdsc2$2", null, null)); synths.add(new AsmFragmentTemplateSynthesisRule("(.*)vwuc2(.*)", null, null , "$1vdsc2$2", null, null));
*/ */
/* /* Removed awaiting optimization
// Rewrite any zeropage pointer as an unsigned word zeropage values // Rewrite any zeropage pointer as an unsigned word zeropage values
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)p..z(.)(.*)", null, null , "$1vwuz$2$3", null, null)); synths.add(new AsmFragmentTemplateSynthesisRule("(.*)p..z(.)(.*)", ".*p..z._deref.*", null , "$1vwuz$2$3", null, null));
// Rewrite any constant pointer as an constant unsigned word // Rewrite any constant pointer as an constant unsigned word
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)p..c(.)(.*)", null, null , "$1vwuc$2$3", null, null)); synths.add(new AsmFragmentTemplateSynthesisRule("(.*)p..c(.)(.*)", ".*p..z._deref.*", null , "$1vwuc$2$3", null, null));
*/ */
// Synthesize some constant pointers as constant words (remove when the above section can be included) // Synthesize some constant pointers as constant words (remove when the above section can be included)

View File

@ -2,6 +2,7 @@ package dk.camelot64.kickc.model.statements;
import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.misc.Interval; import org.antlr.v4.runtime.misc.Interval;
/** Contains information about the source of a program statement */ /** Contains information about the source of a program statement */
@ -15,9 +16,13 @@ public class StatementSource {
@Override @Override
public String toString() { public String toString() {
CharStream stream = context.getStart().getInputStream(); Token contextStart = context.getStart();
Interval interval = new Interval(context.getStart().getStartIndex(), context.getStop().getStopIndex()); if(contextStart != null) {
String sourceMessage = "File "+stream.getSourceName()+"\nLine "+context.getStart().getLine()+ "\n" +stream.getText(interval); CharStream stream = contextStart.getInputStream();
return sourceMessage; Interval interval = new Interval(contextStart.getStartIndex(), context.getStop().getStopIndex());
return "File " + stream.getSourceName() + "\nLine " + contextStart.getLine() + "\n" + stream.getText(interval);
} else {
return "";
}
} }
} }

View File

@ -1,5 +1,6 @@
package dk.camelot64.kickc.model.symbols; package dk.camelot64.kickc.model.symbols;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.Program; import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.Registers; import dk.camelot64.kickc.model.Registers;
import dk.camelot64.kickc.model.VariableRegisterWeights; import dk.camelot64.kickc.model.VariableRegisterWeights;
@ -97,7 +98,7 @@ public abstract class Scope implements Symbol {
public Symbol add(Symbol symbol) { public Symbol add(Symbol symbol) {
if(symbols.get(symbol.getLocalName()) != null) { if(symbols.get(symbol.getLocalName()) != null) {
throw new RuntimeException("Symbol already declared " + symbol.getLocalName()); throw new CompileError("Symbol already declared " + symbol.getLocalName());
} }
symbols.put(symbol.getLocalName(), symbol); symbols.put(symbol.getLocalName(), symbol);
return symbol; return symbol;

View File

@ -299,7 +299,12 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
public Object visitDeclVariable(KickCParser.DeclVariableContext ctx) { public Object visitDeclVariable(KickCParser.DeclVariableContext ctx) {
SymbolType type = (SymbolType) visit(ctx.typeDecl()); SymbolType type = (SymbolType) visit(ctx.typeDecl());
String varName = ctx.NAME().getText(); String varName = ctx.NAME().getText();
VariableUnversioned lValue = getCurrentSymbols().addVariable(varName, type); VariableUnversioned lValue;
try {
lValue = getCurrentSymbols().addVariable(varName, type);
} catch(CompileError e) {
throw new CompileError(e.getMessage(), new StatementSource(ctx));
}
// Add directives // Add directives
addDirectives(type, lValue, ctx.directive()); addDirectives(type, lValue, ctx.directive());
// Array / String variables are implicitly constant // Array / String variables are implicitly constant
@ -669,7 +674,11 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
Variable lValue; Variable lValue;
if(forDeclCtx.typeDecl() != null) { if(forDeclCtx.typeDecl() != null) {
SymbolType type = (SymbolType) visit(forDeclCtx.typeDecl()); SymbolType type = (SymbolType) visit(forDeclCtx.typeDecl());
try {
lValue = getCurrentSymbols().addVariable(varName, type); lValue = getCurrentSymbols().addVariable(varName, type);
} catch(CompileError e) {
throw new CompileError(e.getMessage(), new StatementSource(forDeclCtx));
}
// Add directives // Add directives
addDirectives(type, lValue, forDeclCtx.directive()); addDirectives(type, lValue, forDeclCtx.directive());
} else { } else {

View File

@ -68,7 +68,8 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
throw new CompileError( throw new CompileError(
"Constant variable has a non-matching type \n variable: " + variable.toString(getProgram()) + "Constant variable has a non-matching type \n variable: " + variable.toString(getProgram()) +
"\n value: (" + valueType.toString() + ") " + constVal.calculateLiteral(getScope()) + "\n value: (" + valueType.toString() + ") " + constVal.calculateLiteral(getScope()) +
"\n value definition: " + constVal.toString(getProgram())); "\n value definition: " + constVal.toString(getProgram())
);
} }
} }

View File

@ -4,6 +4,7 @@ import dk.camelot64.kickc.asm.AsmClobber;
import dk.camelot64.kickc.asm.AsmProgram; import dk.camelot64.kickc.asm.AsmProgram;
import dk.camelot64.kickc.asm.AsmSegment; import dk.camelot64.kickc.asm.AsmSegment;
import dk.camelot64.kickc.model.*; import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.statements.StatementSource;
import dk.camelot64.kickc.model.values.RValue; import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.VariableRef; import dk.camelot64.kickc.model.values.VariableRef;
import dk.camelot64.kickc.model.statements.Statement; import dk.camelot64.kickc.model.statements.Statement;
@ -110,16 +111,17 @@ public class Pass4AssertNoCpuClobber extends Pass2Base {
// Alive and not assigned to - clobber not allowed! // Alive and not assigned to - clobber not allowed!
if(clobberRegisters.contains(aliveVarRegister)) { if(clobberRegisters.contains(aliveVarRegister)) {
if(verbose) { if(verbose) {
getLog().append("Error! Alive variable " + aliveVar + " register " + aliveVarRegister + " clobbered by the ASM generated by statement " + statement); throw new CompileError(
"Error! Generated ASM has register clobber problem. " +
"Alive variable "+aliveVar + " register " + aliveVarRegister + " clobbered by the ASM generated by statement "+statement.toString(getProgram(), true),
statement.getSource()
);
} }
clobberProblem = true; clobberProblem = true;
} }
} }
} }
} }
if(verbose && clobberProblem) {
getLog().append(asm.toString(true));
}
return clobberProblem; return clobberProblem;
} }

View File

@ -44,6 +44,11 @@ public class TestPrograms {
AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false); AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false);
} }
@Test
public void testNoLocalScope() throws IOException, URISyntaxException {
assertError("nolocalscope", "Symbol already declared");
}
@Test @Test
public void testTypeMix() throws IOException, URISyntaxException { public void testTypeMix() throws IOException, URISyntaxException {
compileAndCompare("type-mix"); compileAndCompare("type-mix");
@ -288,7 +293,7 @@ public class TestPrograms {
@Test @Test
public void testUnrollInfinite() throws IOException, URISyntaxException { public void testUnrollInfinite() throws IOException, URISyntaxException {
assertError("unroll-infinite", "Loop cannot be unrolled."); assertError("unroll-infinite", "Loop cannot be unrolled.", false);
} }
@Test @Test
@ -1143,7 +1148,7 @@ public class TestPrograms {
@Test @Test
public void testNoReturn() throws IOException, URISyntaxException { public void testNoReturn() throws IOException, URISyntaxException {
assertError("noreturn", "Method must end with a return statement"); assertError("noreturn", "Method must end with a return statement", false);
} }
@Test @Test
@ -1158,7 +1163,7 @@ public class TestPrograms {
@Test @Test
public void testInvalidConstType() throws IOException, URISyntaxException { public void testInvalidConstType() throws IOException, URISyntaxException {
assertError("invalid-consttype", "Constant variable has a non-matching type"); assertError("invalid-consttype", "Constant variable has a non-matching type", false);
} }
@Test @Test
@ -1173,12 +1178,12 @@ public class TestPrograms {
@Test @Test
public void testArrayLengthMismatch() throws IOException, URISyntaxException { public void testArrayLengthMismatch() throws IOException, URISyntaxException {
assertError("array-length-mismatch", "Array length mismatch"); assertError("array-length-mismatch", "Array length mismatch", false);
} }
@Test @Test
public void testStringLengthMismatch() throws IOException, URISyntaxException { public void testStringLengthMismatch() throws IOException, URISyntaxException {
assertError("string-length-mismatch", "Array length mismatch"); assertError("string-length-mismatch", "Array length mismatch", false);
} }
@Test @Test
@ -1188,17 +1193,17 @@ public class TestPrograms {
@Test @Test
public void testRegisterClobber() throws IOException, URISyntaxException { public void testRegisterClobber() throws IOException, URISyntaxException {
assertError("register-clobber", "CLOBBER ERROR"); assertError("register-clobber", "register clobber problem", false);
} }
@Test @Test
public void testRecursionError() throws IOException, URISyntaxException { public void testRecursionError() throws IOException, URISyntaxException {
assertError("recursion-error", "Recursion"); assertError("recursion-error", "Recursion", false);
} }
@Test @Test
public void testRecursionComplexError() throws IOException, URISyntaxException { public void testRecursionComplexError() throws IOException, URISyntaxException {
assertError("recursion-error-complex", "Recursion"); assertError("recursion-error-complex", "Recursion", false);
} }
@Test @Test
@ -1223,7 +1228,7 @@ public class TestPrograms {
@Test @Test
public void testNoInlineInterrupt() throws IOException, URISyntaxException { public void testNoInlineInterrupt() throws IOException, URISyntaxException {
assertError("no-inlineinterrupt", "Interrupts cannot be inlined"); assertError("no-inlineinterrupt", "Interrupts cannot be inlined", false);
} }
@Test @Test
@ -1233,12 +1238,12 @@ public class TestPrograms {
@Test @Test
public void testNoParamInterrupt() throws IOException, URISyntaxException { public void testNoParamInterrupt() throws IOException, URISyntaxException {
assertError("no-paraminterrupt", "Interrupts cannot have parameters."); assertError("no-paraminterrupt", "Interrupts cannot have parameters.", false);
} }
@Test @Test
public void testNoReturnInterrupt() throws IOException, URISyntaxException { public void testNoReturnInterrupt() throws IOException, URISyntaxException {
assertError("no-returninterrupt", "Interrupts cannot return anything."); assertError("no-returninterrupt", "Interrupts cannot return anything.", false);
} }
@Test @Test
@ -1247,12 +1252,20 @@ public class TestPrograms {
} }
private void assertError(String kcFile, String expectError) throws IOException, URISyntaxException { private void assertError(String kcFile, String expectError) throws IOException, URISyntaxException {
assertError(kcFile, expectError, true);
}
private void assertError(String kcFile, String expectError, boolean expectLineNumber) throws IOException, URISyntaxException {
try { try {
compileAndCompare(kcFile); compileAndCompare(kcFile);
} catch(CompileError e) { } catch(CompileError e) {
System.out.println("Got error: " + e.getMessage()); System.out.println("Got error: " + e.getMessage());
// expecting error! // expecting error!
assertTrue("Error message expected '" + expectError + "' - was:" + e.getMessage(), e.getMessage().contains(expectError)); assertTrue("Error message expected '" + expectError + "' - was:" + e.getMessage(), e.getMessage().contains(expectError));
if(expectLineNumber) {
// expecting line number!
assertTrue("Error message expected line number - was:" + e.getMessage(), e.getMessage().contains("Line"));
}
return; return;
} }
fail("Expected compile error."); fail("Expected compile error.");

View File

@ -0,0 +1,10 @@
// Illustrates problem with not introducing local scopes inside loops etc
import "print"
void main() {
for (byte i: 0..5)
print_ln();
for (byte i: 0..5)
print_str_ln(" xxxxx@");
}