1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-02-20 00:29:10 +00:00
This commit is contained in:
Travis Fisher 2019-04-08 17:31:16 -04:00
commit 68a737cf0f
282 changed files with 60720 additions and 12509 deletions

View File

@ -1,14 +1,14 @@
# Contributing
When contributing to this repository, please first discuss the change you wish to make via issue,
email, or any other method with the owner of this repository before making a change.
facebook, or any other method with the owner of this repository before making a change.
## Building KickC
The prerequisites for locally building KickC is Java JDK 8+ and Apache Maven 3+.
The prerequisites for locally building KickC are the following
* https://www.oracle.com/technetwork/java/javase
* https://maven.apache.org
* [Java JDK 8+](https://www.oracle.com/technetwork/java/javase)
* [Apache Maven 3+](https://maven.apache.org)
The steps to build KickC is
@ -16,4 +16,3 @@ The steps to build KickC is
2. Build and package the KickC compiler by entering the source directory and executing `mvn package`

View File

@ -4,13 +4,7 @@ KickC is a compiler for a C-family language creating optimized and readable 6502
The KickC language is classic C with some limitations, some modifications and some extensions to ensure an optimal fit for creating 6502 assembler code.
## BETA
KickC is currently in beta, and crashes quite often resulting in cryptic errors. Also it will some times create ASM code that does not work properly.
Feel free to test it and report any problems or errors you encounter, but do not expect it to produce production quality code.
Also, be prepared that major breaking changes (to syntax, to semantics, etc.) may be implemented in the next versions.
* [Download](https://gitlab.com/camelot/kickc/releases) the newest Releases
* [Download](https://gitlab.com/camelot/kickc/releases) the newest Release
* [Read](https://docs.google.com/document/d/1JE-Lt5apM-g4tZN3LS4TDbPKYgXuBz294enS9Oc4HXM/edit?usp=sharing) the Reference Manual
@ -20,4 +14,11 @@ Also, be prepared that major breaking changes (to syntax, to semantics, etc.) ma
* [Discuss](https://www.facebook.com/groups/302286200587943/) the compiler and receive news on facebook
* [Contribute](https://gitlab.com/camelot/kickc/blob/master/CONTRIBUTING.md) to the development of KickC
* [Contribute](https://gitlab.com/camelot/kickc/blob/master/CONTRIBUTING.md) to the development of KickC
## BETA
KickC is currently in beta, and crashes quite often resulting in cryptic errors.
Also it will at times create ASM code that does not work properly.
Feel free to test it and report any problems or errors you encounter, but do not expect it to produce production quality code.
Also, be prepared that major breaking changes (to syntax, to semantics, etc.) may be implemented in the next versions.

View File

@ -0,0 +1,4 @@
lda #<{c2}
sta {c1}
lda #>{c2}
sta {c1}+1

View File

@ -0,0 +1,6 @@
ldy #0
lda #<{c1}
sta ({z1}),y
iny
lda #>{c1}
sta ({z1}),y

View File

@ -0,0 +1,6 @@
ldy #0
lda {z2}
sta ({z1}),y
iny
lda {z2}+1
sta ({z1}),y

View File

@ -0,0 +1 @@
// No operation needed

View File

@ -0,0 +1,4 @@
lda {z2}
sta {z1}
lda {z2}+1
sta {z1}+1

View File

@ -0,0 +1,4 @@
lda {z2}
sta {z1}
lda {z2}+1
sta {z1}+1

View File

@ -0,0 +1 @@
// No operation needed

View File

@ -0,0 +1,4 @@
lda {z2}
sta {z1}
lda {z2}+1
sta {z1}+1

View File

@ -0,0 +1,4 @@
lda {c1}
sta {z1}
lda {c1}+1
sta {z1}+1

View File

@ -0,0 +1,4 @@
lda #<{c1}
sta {z1}
lda #>{c1}
sta {z1}+1

View File

@ -0,0 +1,4 @@
lda {z2}
sta {z1}
lda {z2}+1
sta {z1}+1

View File

@ -0,0 +1,4 @@
lda {c1},x
sta {z1}
lda {c1}+1,x
sta {z1}+1

View File

@ -0,0 +1,4 @@
lda {c1},y
sta {z1}
lda {c1}+1,y
sta {z1}+1

View File

@ -0,0 +1,4 @@
lda #<{c1}
sta {z1}
lda #>{c1}
sta {z1}+1

View File

@ -0,0 +1,4 @@
clc
lda ({z1}),y
ldy #{c1}
adc ({z1}),y

View File

@ -0,0 +1,2 @@
clc
adc ({z1}),y

View File

@ -0,0 +1,4 @@
lsr
lsr
lsr
lsr

View File

@ -0,0 +1 @@
lda {z1}

View File

@ -0,0 +1,2 @@
ldy #0
lda ({c1}),y

View File

@ -0,0 +1,4 @@
clc
lda ({z1}),y
ldy #{c1}
adc ({z1}),y

View File

@ -0,0 +1 @@
eor {z1}

View File

@ -0,0 +1,2 @@
clc
adc ({z1}),y

View File

@ -0,0 +1,4 @@
lda ({z2}),y
sta {z1}
lda #0
sta {z1}+1

View File

@ -103,6 +103,11 @@ public class CompileLog {
this.verboseStatementSequence = verboseStatementSequence;
}
public CompileLog verboseStatementSequence() {
setVerboseStatementSequence(true);
return this;
}
public void setVerboseComments(boolean verboseComments) {
this.verboseComments = verboseComments;
}
@ -123,10 +128,20 @@ public class CompileLog {
this.verboseSequencePlan = verboseSequencePlan;
}
public CompileLog verboseParse() {
setVerboseParse(true);
return this;
}
public void setVerboseParse(boolean verboseParse) {
this.verboseParse = verboseParse;
}
public CompileLog verboseCreateSsa() {
setVerboseCreateSsa(true);
return this;
}
public void setVerboseCreateSsa(boolean verboseCreateSsa) {
this.verboseCreateSsa = verboseCreateSsa;
}
@ -135,6 +150,11 @@ public class CompileLog {
return verboseUplift;
}
public CompileLog verboseUplift() {
setVerboseUplift(true);
return this;
}
public void setVerboseUplift(boolean verboseUplift) {
this.verboseUplift = verboseUplift;
}
@ -155,6 +175,11 @@ public class CompileLog {
this.verboseFragmentLog = verboseFragmentLog;
}
public CompileLog verboseFragmentLog() {
setVerboseFragmentLog(true);
return this;
}
public boolean isVerboseAsmOptimize() {
return verboseAsmOptimize;
}
@ -167,6 +192,12 @@ public class CompileLog {
return verboseSSAOptimize;
}
public CompileLog setVerboseSSAOptimize() {
setVerboseSSAOptimize(true);
return this;
}
public void setVerboseSSAOptimize(boolean verboseSSAOptimize) {
this.verboseSSAOptimize = verboseSSAOptimize;
}

View File

@ -249,6 +249,7 @@ public class Compiler {
optimizations.add(new Pass2NopCastElimination(program));
optimizations.add(new Pass2EliminateUnusedBlocks(program));
optimizations.add(new Pass2RangeResolving(program));
optimizations.add(new Pass2ConstantCallPointerIdentification(program));
pass2Execute(optimizations);
}
@ -487,6 +488,8 @@ public class Compiler {
pass5Optimizations.add(new Pass5DoubleJumpElimination(program));
pass5Optimizations.add(new Pass5UnreachableCodeElimination(program));
pass5Optimizations.add(new Pass5RelabelLongLabels(program));
pass5Optimizations.add(new Pass5SkipBegin(program));
pass5Optimizations.add(new Pass5AddMainRts(program));
boolean asmOptimized = true;
while(asmOptimized) {
asmOptimized = false;

View File

@ -229,7 +229,7 @@ public class AsmFormat {
* @param boundVar The variable
* @return The ASM parameter to use in the ASM code
*/
static String getAsmParamName(Variable boundVar, ScopeRef codeScopeRef) {
public static String getAsmParamName(Variable boundVar, ScopeRef codeScopeRef) {
ScopeRef varScopeRef = boundVar.getScope().getRef();
String asmName = boundVar.getAsmName() == null ? boundVar.getLocalName() : boundVar.getAsmName();
return getAsmParamName(varScopeRef, asmName, codeScopeRef);
@ -241,7 +241,7 @@ public class AsmFormat {
* @param boundVar The constant
* @return The ASM parameter to use in the ASM code
*/
private static String getAsmParamName(ConstantVar boundVar, ScopeRef codeScopeRef) {
public static String getAsmParamName(ConstantVar boundVar, ScopeRef codeScopeRef) {
ScopeRef varScopeRef = boundVar.getScope().getRef();
String asmName = boundVar.getAsmName() == null ? boundVar.getLocalName() : boundVar.getAsmName();
return getAsmParamName(varScopeRef, asmName, codeScopeRef);

View File

@ -444,9 +444,9 @@ class AsmFragmentTemplateSynthesisRule {
// Rewrite Assignments to *C1 from A
synths.add(new AsmFragmentTemplateSynthesisRule("_deref_pb(.)c1=(.*)", null, null, "vb$1aa=$2", "sta {c1}", null));
// Rewrite Assignments to *Z1 from A
synths.add(new AsmFragmentTemplateSynthesisRule("_deref_pbuz1=(.*)", twoZ1, null, "vbuaa=$1", "ldy #0\n" + "sta ({z1}),y", mapZ));
synths.add(new AsmFragmentTemplateSynthesisRule("_deref_pb(.)z1=(.*)", twoZ1, null, "vb$1aa=$2", "ldy #0\n" + "sta ({z1}),y", mapZ));
// Rewrite Assignments to *Z1 from A
synths.add(new AsmFragmentTemplateSynthesisRule("_deref_pbuz1=(.*z1.*)", null, null, "vbuaa=$1", "ldy #0\n" + "sta ({z1}),y", null));
synths.add(new AsmFragmentTemplateSynthesisRule("_deref_pb(.)z1=(.*z1.*)", null, null, "vb$1aa=$2", "ldy #0\n" + "sta ({z1}),y", null));
// Rewrite _deref_pb.z1_ to _vb.aa_ (if no other Z1s)
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_deref_pb(.)z1(.*)", twoZ1+"|"+rvalAa+"|"+rvalYy+"|"+ lvalDerefZ1, "ldy #0\n"+"lda ({z1}),y", "$1vb$2aa$3", null, mapZ));

View File

@ -549,11 +549,11 @@ public class AsmFragmentTemplateSynthesizer {
}
public class UnknownFragmentException extends RuntimeException {
public static class UnknownFragmentException extends RuntimeException {
private String signature;
UnknownFragmentException(String signature) {
public UnknownFragmentException(String signature) {
super("Fragment not found " + signature);
this.signature = signature;
}

View File

@ -33,6 +33,8 @@ public class ControlFlowGraphBaseVisitor<T> {
return visitJumpTarget((StatementLabel) statement);
} else if(statement instanceof StatementCall) {
return visitCall((StatementCall) statement);
} else if(statement instanceof StatementCallPointer) {
return visitCallPointer((StatementCallPointer) statement);
} else if(statement instanceof StatementPhiBlock) {
return visitPhiBlock((StatementPhiBlock) statement);
} else if(statement instanceof StatementReturn) {
@ -86,6 +88,10 @@ public class ControlFlowGraphBaseVisitor<T> {
return null;
}
public T visitCallPointer(StatementCallPointer call) {
return null;
}
public T visitAsm(StatementAsm asm) {
return null;
}

View File

@ -173,6 +173,14 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor<Obj
return new StatementCall(lValue, procedureName, parameters, orig.getSource(), orig.getComments());
}
@Override
public Object visitCallPointer(StatementCallPointer orig) {
LValue lValue = orig.getlValue();
RValue procedure = orig.getProcedure();
List<RValue> parameters = orig.getParameters();
return new StatementCallPointer(lValue, procedure, parameters, orig.getSource(), orig.getComments());
}
@Override
public StatementProcedureBegin visitProcedureBegin(StatementProcedureBegin orig) {
return new StatementProcedureBegin(orig.getProcedure(), orig.getSource(), orig.getComments());

View File

@ -542,6 +542,44 @@ public abstract class ProgramValue {
}
}
public static class CallPointerProcedure extends ProgramValue {
private final StatementCallPointer call;
CallPointerProcedure(StatementCallPointer call) {
this.call = call;
}
@Override
public Value get() {
return call.getProcedure();
}
@Override
public void set(Value value) {
call.setProcedure((RValue) value);
}
}
public static class CallPointerParameter extends ProgramValue {
private final StatementCallPointer call;
private final int i;
CallPointerParameter(StatementCallPointer call, int i) {
this.call = call;
this.i = i;
}
@Override
public Value get() {
return call.getParameters().get(i);
}
@Override
public void set(Value value) {
call.getParameters().set(i, (RValue) value);
}
}
public static class CondRValue1 extends ProgramValue {
private final StatementConditionalJump statement;
@ -618,7 +656,7 @@ public abstract class ProgramValue {
private final StatementPhiBlock.PhiVariable phiVariable;
private final int i;
PhiValue(StatementPhiBlock.PhiVariable phiVariable, int i) {
public PhiValue(StatementPhiBlock.PhiVariable phiVariable, int i) {
this.phiVariable = phiVariable;
this.i = i;
}

View File

@ -108,6 +108,16 @@ public class ProgramValueIterator {
}
}
execute(new ProgramValue.LValue((StatementLValue) statement), handler, statement, statementsIt, block);
} else if(statement instanceof StatementCallPointer) {
StatementCallPointer call = (StatementCallPointer) statement;
execute(new ProgramValue.CallPointerProcedure((StatementCallPointer) statement), handler, statement, statementsIt, block);
if(call.getParameters() != null) {
int size = call.getParameters().size();
for(int i = 0; i < size; i++) {
execute(new ProgramValue.CallPointerParameter(call, i), handler, statement, statementsIt, block);
}
}
execute(new ProgramValue.LValue((StatementLValue) statement), handler, statement, statementsIt, block);
} else if(statement instanceof StatementConditionalJump) {
execute(new ProgramValue.CondRValue1((StatementConditionalJump) statement), handler, statement, statementsIt, block);
execute(new ProgramValue.CondRValue2((StatementConditionalJump) statement), handler, statement, statementsIt, block);

View File

@ -22,6 +22,8 @@ public class OperatorCastPtr extends OperatorUnary {
public ConstantLiteral calculateLiteral(ConstantLiteral value) {
if(value instanceof ConstantInteger) {
return new ConstantPointer(((ConstantInteger) value).getInteger(), elementType);
} else if(value instanceof ConstantPointer) {
return new ConstantPointer(((ConstantPointer) value).getLocation(), elementType);
}
throw new CompileError("Calculation not implemented " + getOperator() + " " + value);
}

View File

@ -15,12 +15,13 @@ import java.util.List;
*/
public class StatementCall extends StatementBase implements StatementLValue {
/**
* The variable being assigned a value by the call. Can be null.
*/
/** The variable being assigned a value by the call. Can be null. */
private LValue lValue;
/** The name of the procedure called */
private String procedureName;
/** The procedure called. */
private ProcedureRef procedure;
/** The parameter values passed to the procedure. */
private List<RValue> parameters;
public StatementCall(LValue lValue, String procedureName, List<RValue> parameters, StatementSource source, List<Comment> comments) {

View File

@ -0,0 +1,103 @@
package dk.camelot64.kickc.model.statements;
import dk.camelot64.kickc.model.Comment;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.values.LValue;
import dk.camelot64.kickc.model.values.ProcedureRef;
import dk.camelot64.kickc.model.values.RValue;
import java.util.List;
import java.util.Objects;
/**
* Call of a procedure where the called procedure is not directly named, but the result of an expression.
*/
public class StatementCallPointer extends StatementBase implements StatementLValue {
/** The variable being assigned a value by the call. Can be null. */
private LValue lValue;
/** The expression calculating the procedure being called. */
private RValue procedure;
/** The parameter values passed to the procedure. */
private List<RValue> parameters;
public StatementCallPointer(LValue lValue, RValue procedure, List<RValue> parameters, StatementSource source, List<Comment> comments) {
super(null, source, comments);
this.lValue = lValue;
this.procedure = procedure;
this.parameters = parameters;
}
public RValue getProcedure() {
return procedure;
}
public void setProcedure(RValue procedure) {
this.procedure = procedure;
}
public LValue getlValue() {
return lValue;
}
public void setlValue(LValue lValue) {
this.lValue = lValue;
}
public List<RValue> getParameters() {
return parameters;
}
public void setParameters(List<RValue> parameters) {
this.parameters = parameters;
}
public int getNumParameters() {
return parameters.size();
}
public RValue getParameter(int idx) {
return parameters.get(idx);
}
public void clearParameters() {
this.parameters = null;
}
@Override
public String toString(Program program, boolean aliveInfo) {
StringBuilder res = new StringBuilder();
res.append(super.idxString());
if(lValue != null) {
res.append(lValue.toString(program));
res.append("");
}
res.append("call ");
res.append(procedure.toString(program) + " ");
if(parameters != null) {
for(RValue parameter : parameters) {
res.append(parameter.toString(program) + " ");
}
}
if(aliveInfo) {
res.append(super.aliveString(program));
}
return res.toString();
}
@Override
public boolean equals(Object o) {
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
if(!super.equals(o)) return false;
StatementCallPointer that = (StatementCallPointer) o;
return Objects.equals(lValue, that.lValue) &&
Objects.equals(procedure, that.procedure) &&
Objects.equals(parameters, that.parameters);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), lValue, procedure, parameters);
}
}

View File

@ -241,6 +241,19 @@ public abstract class Scope implements Symbol {
return procedures;
}
public Collection<Symbol> getAllSymbols(boolean includeSubscopes) {
ArrayList<Symbol> allSymbols = new ArrayList<>();
for(Symbol symbol : symbols.values()) {
allSymbols.add(symbol);
if(symbol instanceof Scope && includeSubscopes) {
allSymbols.addAll(((Scope) symbol).getAllSymbols(true));
}
}
return allSymbols;
}
public Label addLabel(String name) {
Label symbol = new Label(name, this, false);
add(symbol);

View File

@ -43,16 +43,46 @@ public interface SymbolType {
switch(name) {
case "byte":
return BYTE;
case "unsigned byte":
return BYTE;
case "signed byte":
return SBYTE;
case "char":
return SBYTE;
case "unsigned char":
return BYTE;
case "signed char":
return SBYTE;
case "word":
return WORD;
case "unsigned word":
return WORD;
case "signed word":
return SWORD;
case "short":
return SWORD;
case "unsigned short":
return WORD;
case "signed short":
return SWORD;
case "int":
return SWORD;
case "unsigned int":
return WORD;
case "signed int":
return SWORD;
case "dword":
return DWORD;
case "unsigned dword":
return DWORD;
case "signed dword":
return SDWORD;
case "long":
return SDWORD;
case "unsigned long":
return DWORD;
case "signed long":
return SDWORD;
case "string":
return STRING;
case "bool":

View File

@ -6,9 +6,7 @@ import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.operators.Operator;
import dk.camelot64.kickc.model.operators.OperatorBinary;
import dk.camelot64.kickc.model.operators.OperatorUnary;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.statements.StatementCall;
import dk.camelot64.kickc.model.statements.StatementLValue;
import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.values.*;
@ -327,6 +325,47 @@ public class SymbolTypeInference {
}
}
public static void inferCallPointerLValue(Program program, StatementCallPointer call, boolean reinfer) {
ProgramScope programScope = program.getScope();
LValue lValue = call.getlValue();
if(lValue instanceof VariableRef) {
Variable symbol = programScope.getVariable((VariableRef) lValue);
if(SymbolType.VAR.equals(symbol.getType()) || (reinfer && symbol.isInferredType())) {
SymbolType procedureType = inferType(programScope, call.getProcedure());
if(procedureType instanceof SymbolTypeProcedure) {
SymbolType returnType = ((SymbolTypeProcedure) procedureType).getReturnType();
setInferedType(program, call, symbol, returnType);
}
}
}
}
public static void inferPhiVariable(Program program, StatementPhiBlock.PhiVariable phiVariable, boolean reinfer) {
ProgramScope programScope = program.getScope();
Variable symbol = programScope.getVariable(phiVariable.getVariable());
if(SymbolType.VAR.equals(symbol.getType()) || (reinfer && symbol.isInferredType())) {
SymbolType type = null;
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
RValue rValue = phiRValue.getrValue();
SymbolType valueType = inferType(programScope, rValue);
if(type == null) {
type = valueType;
} else {
SymbolType newType = intersectTypes(type, valueType);
if(newType == null) {
throw new CompileError("Types not compatible " + type + " and " + valueType);
}
type = newType;
}
}
if(!SymbolType.VAR.equals(symbol.getType()) && !type.equals(symbol.getType())) {
program.getLog().append("Inferred type updated to " + type + " for " + symbol.toString(program));
}
symbol.setTypeInferred(type);
}
}
public static void inferAssignmentLValue(Program program, StatementAssignment assignment, boolean reinfer) {
ProgramScope programScope = program.getScope();
LValue lValue = assignment.getlValue();
@ -365,9 +404,9 @@ public class SymbolTypeInference {
}
}
private static void setInferedType(Program program, StatementLValue statementLValue, Variable symbol, SymbolType type) {
private static void setInferedType(Program program, Statement statement, Variable symbol, SymbolType type) {
if(!SymbolType.VAR.equals(symbol.getType()) && !type.equals(symbol.getType())) {
program.getLog().append("Inferred type updated to " + type + " in " + statementLValue.toString(program, false));
program.getLog().append("Inferred type updated to " + type + " in " + statement.toString(program, false));
}
symbol.setTypeInferred(type);
}
@ -377,6 +416,8 @@ public class SymbolTypeInference {
inferAssignmentLValue(program, (StatementAssignment) statementLValue, reinfer);
} else if(statementLValue instanceof StatementCall) {
inferCallLValue(program, (StatementCall) statementLValue, reinfer);
} else if(statementLValue instanceof StatementCallPointer) {
inferCallPointerLValue(program, (StatementCallPointer) statementLValue, reinfer);
} else {
throw new RuntimeException("LValue statement not implemented " + statementLValue);
}

View File

@ -39,7 +39,9 @@ parameterListDecl
: parameterDecl (',' parameterDecl)* ;
parameterDecl
: directive* typeDecl directive* NAME ;
: directive* typeDecl directive* NAME #parameterDeclType
| SIMPLETYPE #parameterDeclVoid
;
directive
: 'const' #directiveConst
@ -82,7 +84,7 @@ forIteration
typeDecl
: '(' typeDecl ')' #typePar
| SIMPLETYPE #typeSimple
| 'signed' SIMPLETYPE #typeSignedSimple
| ('signed'|'unsigned') SIMPLETYPE #typeSignedSimple
| typeDecl '*' #typePtr
| typeDecl '[' (expr)? ']' #typeArray
| typeDecl '(' ')' #typeProcedure
@ -90,7 +92,7 @@ typeDecl
expr
: '(' expr ')' #exprPar
| NAME '(' parameterList? ')' #exprCall
| expr '(' parameterList? ')' #exprCall
| expr '[' expr ']' #exprArray
| '(' typeDecl ')' expr #exprCast
| ('--' | '++' ) expr #exprPreMod
@ -107,6 +109,7 @@ expr
| expr ( '|' ) expr #exprBinary
| expr ( '&&' ) expr #exprBinary
| expr ( '||' ) expr #exprBinary
| expr '?' expr ':' expr #exprTernary
| <assoc=right> expr '=' expr #exprAssignment
| <assoc=right> expr ('+=' | '-=' | '*=' | '/=' | '%=' | '<<=' | '>>=' | '&=' | '|=' | '^=' ) expr #exprAssignmentCompound
| '{' expr (',' expr )* '}' #initList
@ -193,7 +196,7 @@ MNEMONIC:
KICKASM: '{{' .*? '}}';
SIMPLETYPE: 'byte' | 'word' | 'dword' | 'bool' | 'void' ;
SIMPLETYPE: 'byte' | 'word' | 'dword' | 'bool' | 'char' | 'short' | 'int' | 'long' | 'void' ;
STRING : '"' ('\\"' | ~'"')* '"';
CHAR : '\'' ('\\\'' | ~'\'' ) '\'';
BOOLEAN : 'true' | 'false';

View File

@ -69,26 +69,28 @@ T__67=68
T__68=69
T__69=70
T__70=71
MNEMONIC=72
KICKASM=73
SIMPLETYPE=74
STRING=75
CHAR=76
BOOLEAN=77
NUMBER=78
NUMFLOAT=79
BINFLOAT=80
DECFLOAT=81
HEXFLOAT=82
NUMINT=83
BININTEGER=84
DECINTEGER=85
HEXINTEGER=86
NAME=87
ASMREL=88
WS=89
COMMENT_LINE=90
COMMENT_BLOCK=91
T__71=72
T__72=73
MNEMONIC=74
KICKASM=75
SIMPLETYPE=76
STRING=77
CHAR=78
BOOLEAN=79
NUMBER=80
NUMFLOAT=81
BINFLOAT=82
DECFLOAT=83
HEXFLOAT=84
NUMINT=85
BININTEGER=86
DECINTEGER=87
HEXINTEGER=88
NAME=89
ASMREL=90
WS=91
COMMENT_LINE=92
COMMENT_BLOCK=93
'import'=1
'='=2
';'=3
@ -116,47 +118,49 @@ COMMENT_BLOCK=91
':'=25
'..'=26
'signed'=27
'*'=28
'['=29
']'=30
'--'=31
'++'=32
'+'=33
'-'=34
'!'=35
'&'=36
'~'=37
'>>'=38
'<<'=39
'/'=40
'%'=41
'<'=42
'>'=43
'=='=44
'!='=45
'<='=46
'>='=47
'^'=48
'|'=49
'&&'=50
'||'=51
'+='=52
'-='=53
'*='=54
'/='=55
'%='=56
'<<='=57
'>>='=58
'&='=59
'|='=60
'^='=61
'kickasm'=62
'resource'=63
'uses'=64
'clobbers'=65
'bytes'=66
'cycles'=67
'pc'=68
'.byte'=69
'#'=70
'.'=71
'unsigned'=28
'*'=29
'['=30
']'=31
'--'=32
'++'=33
'+'=34
'-'=35
'!'=36
'&'=37
'~'=38
'>>'=39
'<<'=40
'/'=41
'%'=42
'<'=43
'>'=44
'=='=45
'!='=46
'<='=47
'>='=48
'^'=49
'|'=50
'&&'=51
'||'=52
'?'=53
'+='=54
'-='=55
'*='=56
'/='=57
'%='=58
'<<='=59
'>>='=60
'&='=61
'|='=62
'^='=63
'kickasm'=64
'resource'=65
'uses'=66
'clobbers'=67
'bytes'=68
'cycles'=69
'pc'=70
'.byte'=71
'#'=72
'.'=73

View File

@ -1,4 +1,4 @@
// Generated from C:/c64/kickc/src/main/java/dk/camelot64/kickc/parser\KickC.g4 by ANTLR 4.7
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickC.g4 by ANTLR 4.7
package dk.camelot64.kickc.parser;
import org.antlr.v4.runtime.ParserRuleContext;
@ -124,13 +124,25 @@ public class KickCBaseListener implements KickCListener {
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterParameterDecl(KickCParser.ParameterDeclContext ctx) { }
@Override public void enterParameterDeclType(KickCParser.ParameterDeclTypeContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitParameterDecl(KickCParser.ParameterDeclContext ctx) { }
@Override public void exitParameterDeclType(KickCParser.ParameterDeclTypeContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterParameterDeclVoid(KickCParser.ParameterDeclVoidContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitParameterDeclVoid(KickCParser.ParameterDeclVoidContext ctx) { }
/**
* {@inheritDoc}
*
@ -659,6 +671,18 @@ public class KickCBaseListener implements KickCListener {
* <p>The default implementation does nothing.</p>
*/
@Override public void exitExprId(KickCParser.ExprIdContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterExprTernary(KickCParser.ExprTernaryContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitExprTernary(KickCParser.ExprTernaryContext ctx) { }
/**
* {@inheritDoc}
*

View File

@ -1,4 +1,4 @@
// Generated from C:/c64/kickc/src/main/java/dk/camelot64/kickc/parser\KickC.g4 by ANTLR 4.7
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickC.g4 by ANTLR 4.7
package dk.camelot64.kickc.parser;
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
@ -80,7 +80,14 @@ public class KickCBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitParameterDecl(KickCParser.ParameterDeclContext ctx) { return visitChildren(ctx); }
@Override public T visitParameterDeclType(KickCParser.ParameterDeclTypeContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitParameterDeclVoid(KickCParser.ParameterDeclVoidContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
@ -389,6 +396,13 @@ public class KickCBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitExprId(KickCParser.ExprIdContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitExprTernary(KickCParser.ExprTernaryContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*

View File

@ -1,4 +1,4 @@
// Generated from C:/c64/kickc/src/main/java/dk/camelot64/kickc/parser\KickC.g4 by ANTLR 4.7
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickC.g4 by ANTLR 4.7
package dk.camelot64.kickc.parser;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.CharStream;
@ -26,10 +26,11 @@ public class KickCLexer extends Lexer {
T__45=46, T__46=47, T__47=48, T__48=49, T__49=50, T__50=51, T__51=52,
T__52=53, T__53=54, T__54=55, T__55=56, T__56=57, T__57=58, T__58=59,
T__59=60, T__60=61, T__61=62, T__62=63, T__63=64, T__64=65, T__65=66,
T__66=67, T__67=68, T__68=69, T__69=70, T__70=71, MNEMONIC=72, KICKASM=73,
SIMPLETYPE=74, STRING=75, CHAR=76, BOOLEAN=77, NUMBER=78, NUMFLOAT=79,
BINFLOAT=80, DECFLOAT=81, HEXFLOAT=82, NUMINT=83, BININTEGER=84, DECINTEGER=85,
HEXINTEGER=86, NAME=87, ASMREL=88, WS=89, COMMENT_LINE=90, COMMENT_BLOCK=91;
T__66=67, T__67=68, T__68=69, T__69=70, T__70=71, T__71=72, T__72=73,
MNEMONIC=74, KICKASM=75, SIMPLETYPE=76, STRING=77, CHAR=78, BOOLEAN=79,
NUMBER=80, NUMFLOAT=81, BINFLOAT=82, DECFLOAT=83, HEXFLOAT=84, NUMINT=85,
BININTEGER=86, DECINTEGER=87, HEXINTEGER=88, NAME=89, ASMREL=90, WS=91,
COMMENT_LINE=92, COMMENT_BLOCK=93;
public static String[] channelNames = {
"DEFAULT_TOKEN_CHANNEL", "HIDDEN"
};
@ -47,23 +48,23 @@ public class KickCLexer extends Lexer {
"T__41", "T__42", "T__43", "T__44", "T__45", "T__46", "T__47", "T__48",
"T__49", "T__50", "T__51", "T__52", "T__53", "T__54", "T__55", "T__56",
"T__57", "T__58", "T__59", "T__60", "T__61", "T__62", "T__63", "T__64",
"T__65", "T__66", "T__67", "T__68", "T__69", "T__70", "MNEMONIC", "KICKASM",
"SIMPLETYPE", "STRING", "CHAR", "BOOLEAN", "NUMBER", "NUMFLOAT", "BINFLOAT",
"DECFLOAT", "HEXFLOAT", "NUMINT", "BININTEGER", "DECINTEGER", "HEXINTEGER",
"BINDIGIT", "DECDIGIT", "HEXDIGIT", "NAME", "NAME_START", "NAME_CHAR",
"ASMREL", "WS", "COMMENT_LINE", "COMMENT_BLOCK"
"T__65", "T__66", "T__67", "T__68", "T__69", "T__70", "T__71", "T__72",
"MNEMONIC", "KICKASM", "SIMPLETYPE", "STRING", "CHAR", "BOOLEAN", "NUMBER",
"NUMFLOAT", "BINFLOAT", "DECFLOAT", "HEXFLOAT", "NUMINT", "BININTEGER",
"DECINTEGER", "HEXINTEGER", "BINDIGIT", "DECDIGIT", "HEXDIGIT", "NAME",
"NAME_START", "NAME_CHAR", "ASMREL", "WS", "COMMENT_LINE", "COMMENT_BLOCK"
};
private static final String[] _LITERAL_NAMES = {
null, "'import'", "'='", "';'", "'('", "')'", "'{'", "'}'", "','", "'const'",
"'extern'", "'align'", "'register'", "'inline'", "'volatile'", "'interrupt'",
"'if'", "'else'", "'while'", "'do'", "'for'", "'return'", "'break'", "'continue'",
"'asm'", "':'", "'..'", "'signed'", "'*'", "'['", "']'", "'--'", "'++'",
"'+'", "'-'", "'!'", "'&'", "'~'", "'>>'", "'<<'", "'/'", "'%'", "'<'",
"'>'", "'=='", "'!='", "'<='", "'>='", "'^'", "'|'", "'&&'", "'||'", "'+='",
"'-='", "'*='", "'/='", "'%='", "'<<='", "'>>='", "'&='", "'|='", "'^='",
"'kickasm'", "'resource'", "'uses'", "'clobbers'", "'bytes'", "'cycles'",
"'pc'", "'.byte'", "'#'", "'.'"
"'asm'", "':'", "'..'", "'signed'", "'unsigned'", "'*'", "'['", "']'",
"'--'", "'++'", "'+'", "'-'", "'!'", "'&'", "'~'", "'>>'", "'<<'", "'/'",
"'%'", "'<'", "'>'", "'=='", "'!='", "'<='", "'>='", "'^'", "'|'", "'&&'",
"'||'", "'?'", "'+='", "'-='", "'*='", "'/='", "'%='", "'<<='", "'>>='",
"'&='", "'|='", "'^='", "'kickasm'", "'resource'", "'uses'", "'clobbers'",
"'bytes'", "'cycles'", "'pc'", "'.byte'", "'#'", "'.'"
};
private static final String[] _SYMBOLIC_NAMES = {
null, null, null, null, null, null, null, null, null, null, null, null,
@ -72,8 +73,8 @@ public class KickCLexer extends Lexer {
null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null,
"MNEMONIC", "KICKASM", "SIMPLETYPE", "STRING", "CHAR", "BOOLEAN", "NUMBER",
"NUMFLOAT", "BINFLOAT", "DECFLOAT", "HEXFLOAT", "NUMINT", "BININTEGER",
null, null, "MNEMONIC", "KICKASM", "SIMPLETYPE", "STRING", "CHAR", "BOOLEAN",
"NUMBER", "NUMFLOAT", "BINFLOAT", "DECFLOAT", "HEXFLOAT", "NUMINT", "BININTEGER",
"DECINTEGER", "HEXINTEGER", "NAME", "ASMREL", "WS", "COMMENT_LINE", "COMMENT_BLOCK"
};
public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
@ -134,7 +135,7 @@ public class KickCLexer extends Lexer {
public ATN getATN() { return _ATN; }
public static final String _serializedATN =
"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2]\u039a\b\1\4\2\t"+
"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2_\u03b9\b\1\4\2\t"+
"\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+
"\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+
"\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+
@ -145,326 +146,338 @@ public class KickCLexer extends Lexer {
"\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4I"+
"\tI\4J\tJ\4K\tK\4L\tL\4M\tM\4N\tN\4O\tO\4P\tP\4Q\tQ\4R\tR\4S\tS\4T\tT"+
"\4U\tU\4V\tV\4W\tW\4X\tX\4Y\tY\4Z\tZ\4[\t[\4\\\t\\\4]\t]\4^\t^\4_\t_\4"+
"`\t`\4a\ta\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6"+
"\3\7\3\7\3\b\3\b\3\t\3\t\3\n\3\n\3\n\3\n\3\n\3\n\3\13\3\13\3\13\3\13\3"+
"\13\3\13\3\13\3\f\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r"+
"\3\r\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3\17\3\17"+
"\3\17\3\17\3\17\3\20\3\20\3\20\3\20\3\20\3\20\3\20\3\20\3\20\3\20\3\21"+
"\3\21\3\21\3\22\3\22\3\22\3\22\3\22\3\23\3\23\3\23\3\23\3\23\3\23\3\24"+
"\3\24\3\24\3\25\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\26\3\26\3\26\3\27"+
"\3\27\3\27\3\27\3\27\3\27\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30"+
"\3\31\3\31\3\31\3\31\3\32\3\32\3\33\3\33\3\33\3\34\3\34\3\34\3\34\3\34"+
"\3\34\3\34\3\35\3\35\3\36\3\36\3\37\3\37\3 \3 \3 \3!\3!\3!\3\"\3\"\3#"+
"\3#\3$\3$\3%\3%\3&\3&\3\'\3\'\3\'\3(\3(\3(\3)\3)\3*\3*\3+\3+\3,\3,\3-"+
"\3-\3-\3.\3.\3.\3/\3/\3/\3\60\3\60\3\60\3\61\3\61\3\62\3\62\3\63\3\63"+
"\3\63\3\64\3\64\3\64\3\65\3\65\3\65\3\66\3\66\3\66\3\67\3\67\3\67\38\3"+
"8\38\39\39\39\3:\3:\3:\3:\3;\3;\3;\3;\3<\3<\3<\3=\3=\3=\3>\3>\3>\3?\3"+
"?\3?\3?\3?\3?\3?\3?\3@\3@\3@\3@\3@\3@\3@\3@\3@\3A\3A\3A\3A\3A\3B\3B\3"+
"B\3B\3B\3B\3B\3B\3B\3C\3C\3C\3C\3C\3C\3D\3D\3D\3D\3D\3D\3D\3E\3E\3E\3"+
"F\3F\3F\3F\3F\3F\3G\3G\3H\3H\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3"+
"I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3"+
"I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3"+
"I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3"+
"I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3"+
"I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3"+
"I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3"+
"I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3"+
"I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3"+
"I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3I\3"+
"I\3I\5I\u02bb\nI\3J\3J\3J\3J\7J\u02c1\nJ\fJ\16J\u02c4\13J\3J\3J\3J\3K"+
"\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\5K\u02de"+
"\nK\3L\3L\3L\3L\7L\u02e4\nL\fL\16L\u02e7\13L\3L\3L\3M\3M\3M\3M\5M\u02ef"+
"\nM\3M\3M\3N\3N\3N\3N\3N\3N\3N\3N\3N\5N\u02fc\nN\3O\3O\5O\u0300\nO\3P"+
"\3P\3P\5P\u0305\nP\3Q\3Q\3Q\3Q\3Q\5Q\u030c\nQ\3Q\7Q\u030f\nQ\fQ\16Q\u0312"+
"\13Q\3Q\3Q\6Q\u0316\nQ\rQ\16Q\u0317\3R\7R\u031b\nR\fR\16R\u031e\13R\3"+
"R\3R\6R\u0322\nR\rR\16R\u0323\3S\3S\3S\3S\3S\5S\u032b\nS\3S\7S\u032e\n"+
"S\fS\16S\u0331\13S\3S\3S\6S\u0335\nS\rS\16S\u0336\3T\3T\3T\5T\u033c\n"+
"T\3U\3U\3U\6U\u0341\nU\rU\16U\u0342\3U\3U\6U\u0347\nU\rU\16U\u0348\5U"+
"\u034b\nU\3V\6V\u034e\nV\rV\16V\u034f\3W\3W\3W\3W\3W\5W\u0357\nW\3W\6"+
"W\u035a\nW\rW\16W\u035b\3X\3X\3Y\3Y\3Z\3Z\3[\3[\7[\u0366\n[\f[\16[\u0369"+
"\13[\3\\\3\\\3]\3]\3^\3^\7^\u0371\n^\f^\16^\u0374\13^\3^\6^\u0377\n^\r"+
"^\16^\u0378\3_\6_\u037c\n_\r_\16_\u037d\3_\3_\3`\3`\3`\3`\7`\u0386\n`"+
"\f`\16`\u0389\13`\3`\3`\3a\3a\3a\3a\7a\u0391\na\fa\16a\u0394\13a\3a\3"+
"a\3a\3a\3a\4\u02c2\u0392\2b\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25"+
"\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32"+
"\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]\60_\61a"+
"\62c\63e\64g\65i\66k\67m8o9q:s;u<w=y>{?}@\177A\u0081B\u0083C\u0085D\u0087"+
"E\u0089F\u008bG\u008dH\u008fI\u0091J\u0093K\u0095L\u0097M\u0099N\u009b"+
"O\u009dP\u009fQ\u00a1R\u00a3S\u00a5T\u00a7U\u00a9V\u00abW\u00adX\u00af"+
"\2\u00b1\2\u00b3\2\u00b5Y\u00b7\2\u00b9\2\u00bbZ\u00bd[\u00bf\\\u00c1"+
"]\3\2\r\3\2$$\3\2))\4\2DDdd\3\2\62\63\3\2\62;\5\2\62;CHch\5\2C\\aac|\6"+
"\2\62;C\\aac|\4\2--//\6\2\13\f\17\17\"\"\u00a2\u00a2\4\2\f\f\17\17\2\u0402"+
"\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2"+
"\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2"+
"\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2"+
"\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2"+
"\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3"+
"\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2"+
"\2\2I\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2"+
"U\3\2\2\2\2W\3\2\2\2\2Y\3\2\2\2\2[\3\2\2\2\2]\3\2\2\2\2_\3\2\2\2\2a\3"+
"\2\2\2\2c\3\2\2\2\2e\3\2\2\2\2g\3\2\2\2\2i\3\2\2\2\2k\3\2\2\2\2m\3\2\2"+
"\2\2o\3\2\2\2\2q\3\2\2\2\2s\3\2\2\2\2u\3\2\2\2\2w\3\2\2\2\2y\3\2\2\2\2"+
"{\3\2\2\2\2}\3\2\2\2\2\177\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3\2\2\2\2\u0085"+
"\3\2\2\2\2\u0087\3\2\2\2\2\u0089\3\2\2\2\2\u008b\3\2\2\2\2\u008d\3\2\2"+
"\2\2\u008f\3\2\2\2\2\u0091\3\2\2\2\2\u0093\3\2\2\2\2\u0095\3\2\2\2\2\u0097"+
"\3\2\2\2\2\u0099\3\2\2\2\2\u009b\3\2\2\2\2\u009d\3\2\2\2\2\u009f\3\2\2"+
"\2\2\u00a1\3\2\2\2\2\u00a3\3\2\2\2\2\u00a5\3\2\2\2\2\u00a7\3\2\2\2\2\u00a9"+
"\3\2\2\2\2\u00ab\3\2\2\2\2\u00ad\3\2\2\2\2\u00b5\3\2\2\2\2\u00bb\3\2\2"+
"\2\2\u00bd\3\2\2\2\2\u00bf\3\2\2\2\2\u00c1\3\2\2\2\3\u00c3\3\2\2\2\5\u00ca"+
"\3\2\2\2\7\u00cc\3\2\2\2\t\u00ce\3\2\2\2\13\u00d0\3\2\2\2\r\u00d2\3\2"+
"\2\2\17\u00d4\3\2\2\2\21\u00d6\3\2\2\2\23\u00d8\3\2\2\2\25\u00de\3\2\2"+
"\2\27\u00e5\3\2\2\2\31\u00eb\3\2\2\2\33\u00f4\3\2\2\2\35\u00fb\3\2\2\2"+
"\37\u0104\3\2\2\2!\u010e\3\2\2\2#\u0111\3\2\2\2%\u0116\3\2\2\2\'\u011c"+
"\3\2\2\2)\u011f\3\2\2\2+\u0123\3\2\2\2-\u012a\3\2\2\2/\u0130\3\2\2\2\61"+
"\u0139\3\2\2\2\63\u013d\3\2\2\2\65\u013f\3\2\2\2\67\u0142\3\2\2\29\u0149"+
"\3\2\2\2;\u014b\3\2\2\2=\u014d\3\2\2\2?\u014f\3\2\2\2A\u0152\3\2\2\2C"+
"\u0155\3\2\2\2E\u0157\3\2\2\2G\u0159\3\2\2\2I\u015b\3\2\2\2K\u015d\3\2"+
"\2\2M\u015f\3\2\2\2O\u0162\3\2\2\2Q\u0165\3\2\2\2S\u0167\3\2\2\2U\u0169"+
"\3\2\2\2W\u016b\3\2\2\2Y\u016d\3\2\2\2[\u0170\3\2\2\2]\u0173\3\2\2\2_"+
"\u0176\3\2\2\2a\u0179\3\2\2\2c\u017b\3\2\2\2e\u017d\3\2\2\2g\u0180\3\2"+
"\2\2i\u0183\3\2\2\2k\u0186\3\2\2\2m\u0189\3\2\2\2o\u018c\3\2\2\2q\u018f"+
"\3\2\2\2s\u0192\3\2\2\2u\u0196\3\2\2\2w\u019a\3\2\2\2y\u019d\3\2\2\2{"+
"\u01a0\3\2\2\2}\u01a3\3\2\2\2\177\u01ab\3\2\2\2\u0081\u01b4\3\2\2\2\u0083"+
"\u01b9\3\2\2\2\u0085\u01c2\3\2\2\2\u0087\u01c8\3\2\2\2\u0089\u01cf\3\2"+
"\2\2\u008b\u01d2\3\2\2\2\u008d\u01d8\3\2\2\2\u008f\u01da\3\2\2\2\u0091"+
"\u02ba\3\2\2\2\u0093\u02bc\3\2\2\2\u0095\u02dd\3\2\2\2\u0097\u02df\3\2"+
"\2\2\u0099\u02ea\3\2\2\2\u009b\u02fb\3\2\2\2\u009d\u02ff\3\2\2\2\u009f"+
"\u0304\3\2\2\2\u00a1\u030b\3\2\2\2\u00a3\u031c\3\2\2\2\u00a5\u032a\3\2"+
"\2\2\u00a7\u033b\3\2\2\2\u00a9\u034a\3\2\2\2\u00ab\u034d\3\2\2\2\u00ad"+
"\u0356\3\2\2\2\u00af\u035d\3\2\2\2\u00b1\u035f\3\2\2\2\u00b3\u0361\3\2"+
"\2\2\u00b5\u0363\3\2\2\2\u00b7\u036a\3\2\2\2\u00b9\u036c\3\2\2\2\u00bb"+
"\u036e\3\2\2\2\u00bd\u037b\3\2\2\2\u00bf\u0381\3\2\2\2\u00c1\u038c\3\2"+
"\2\2\u00c3\u00c4\7k\2\2\u00c4\u00c5\7o\2\2\u00c5\u00c6\7r\2\2\u00c6\u00c7"+
"\7q\2\2\u00c7\u00c8\7t\2\2\u00c8\u00c9\7v\2\2\u00c9\4\3\2\2\2\u00ca\u00cb"+
"\7?\2\2\u00cb\6\3\2\2\2\u00cc\u00cd\7=\2\2\u00cd\b\3\2\2\2\u00ce\u00cf"+
"\7*\2\2\u00cf\n\3\2\2\2\u00d0\u00d1\7+\2\2\u00d1\f\3\2\2\2\u00d2\u00d3"+
"\7}\2\2\u00d3\16\3\2\2\2\u00d4\u00d5\7\177\2\2\u00d5\20\3\2\2\2\u00d6"+
"\u00d7\7.\2\2\u00d7\22\3\2\2\2\u00d8\u00d9\7e\2\2\u00d9\u00da\7q\2\2\u00da"+
"\u00db\7p\2\2\u00db\u00dc\7u\2\2\u00dc\u00dd\7v\2\2\u00dd\24\3\2\2\2\u00de"+
"\u00df\7g\2\2\u00df\u00e0\7z\2\2\u00e0\u00e1\7v\2\2\u00e1\u00e2\7g\2\2"+
"\u00e2\u00e3\7t\2\2\u00e3\u00e4\7p\2\2\u00e4\26\3\2\2\2\u00e5\u00e6\7"+
"c\2\2\u00e6\u00e7\7n\2\2\u00e7\u00e8\7k\2\2\u00e8\u00e9\7i\2\2\u00e9\u00ea"+
"\7p\2\2\u00ea\30\3\2\2\2\u00eb\u00ec\7t\2\2\u00ec\u00ed\7g\2\2\u00ed\u00ee"+
"\7i\2\2\u00ee\u00ef\7k\2\2\u00ef\u00f0\7u\2\2\u00f0\u00f1\7v\2\2\u00f1"+
"\u00f2\7g\2\2\u00f2\u00f3\7t\2\2\u00f3\32\3\2\2\2\u00f4\u00f5\7k\2\2\u00f5"+
"\u00f6\7p\2\2\u00f6\u00f7\7n\2\2\u00f7\u00f8\7k\2\2\u00f8\u00f9\7p\2\2"+
"\u00f9\u00fa\7g\2\2\u00fa\34\3\2\2\2\u00fb\u00fc\7x\2\2\u00fc\u00fd\7"+
"q\2\2\u00fd\u00fe\7n\2\2\u00fe\u00ff\7c\2\2\u00ff\u0100\7v\2\2\u0100\u0101"+
"\7k\2\2\u0101\u0102\7n\2\2\u0102\u0103\7g\2\2\u0103\36\3\2\2\2\u0104\u0105"+
"\7k\2\2\u0105\u0106\7p\2\2\u0106\u0107\7v\2\2\u0107\u0108\7g\2\2\u0108"+
"\u0109\7t\2\2\u0109\u010a\7t\2\2\u010a\u010b\7w\2\2\u010b\u010c\7r\2\2"+
"\u010c\u010d\7v\2\2\u010d \3\2\2\2\u010e\u010f\7k\2\2\u010f\u0110\7h\2"+
"\2\u0110\"\3\2\2\2\u0111\u0112\7g\2\2\u0112\u0113\7n\2\2\u0113\u0114\7"+
"u\2\2\u0114\u0115\7g\2\2\u0115$\3\2\2\2\u0116\u0117\7y\2\2\u0117\u0118"+
"\7j\2\2\u0118\u0119\7k\2\2\u0119\u011a\7n\2\2\u011a\u011b\7g\2\2\u011b"+
"&\3\2\2\2\u011c\u011d\7f\2\2\u011d\u011e\7q\2\2\u011e(\3\2\2\2\u011f\u0120"+
"\7h\2\2\u0120\u0121\7q\2\2\u0121\u0122\7t\2\2\u0122*\3\2\2\2\u0123\u0124"+
"\7t\2\2\u0124\u0125\7g\2\2\u0125\u0126\7v\2\2\u0126\u0127\7w\2\2\u0127"+
"\u0128\7t\2\2\u0128\u0129\7p\2\2\u0129,\3\2\2\2\u012a\u012b\7d\2\2\u012b"+
"\u012c\7t\2\2\u012c\u012d\7g\2\2\u012d\u012e\7c\2\2\u012e\u012f\7m\2\2"+
"\u012f.\3\2\2\2\u0130\u0131\7e\2\2\u0131\u0132\7q\2\2\u0132\u0133\7p\2"+
"\2\u0133\u0134\7v\2\2\u0134\u0135\7k\2\2\u0135\u0136\7p\2\2\u0136\u0137"+
"\7w\2\2\u0137\u0138\7g\2\2\u0138\60\3\2\2\2\u0139\u013a\7c\2\2\u013a\u013b"+
"\7u\2\2\u013b\u013c\7o\2\2\u013c\62\3\2\2\2\u013d\u013e\7<\2\2\u013e\64"+
"\3\2\2\2\u013f\u0140\7\60\2\2\u0140\u0141\7\60\2\2\u0141\66\3\2\2\2\u0142"+
"\u0143\7u\2\2\u0143\u0144\7k\2\2\u0144\u0145\7i\2\2\u0145\u0146\7p\2\2"+
"\u0146\u0147\7g\2\2\u0147\u0148\7f\2\2\u01488\3\2\2\2\u0149\u014a\7,\2"+
"\2\u014a:\3\2\2\2\u014b\u014c\7]\2\2\u014c<\3\2\2\2\u014d\u014e\7_\2\2"+
"\u014e>\3\2\2\2\u014f\u0150\7/\2\2\u0150\u0151\7/\2\2\u0151@\3\2\2\2\u0152"+
"\u0153\7-\2\2\u0153\u0154\7-\2\2\u0154B\3\2\2\2\u0155\u0156\7-\2\2\u0156"+
"D\3\2\2\2\u0157\u0158\7/\2\2\u0158F\3\2\2\2\u0159\u015a\7#\2\2\u015aH"+
"\3\2\2\2\u015b\u015c\7(\2\2\u015cJ\3\2\2\2\u015d\u015e\7\u0080\2\2\u015e"+
"L\3\2\2\2\u015f\u0160\7@\2\2\u0160\u0161\7@\2\2\u0161N\3\2\2\2\u0162\u0163"+
"\7>\2\2\u0163\u0164\7>\2\2\u0164P\3\2\2\2\u0165\u0166\7\61\2\2\u0166R"+
"\3\2\2\2\u0167\u0168\7\'\2\2\u0168T\3\2\2\2\u0169\u016a\7>\2\2\u016aV"+
"\3\2\2\2\u016b\u016c\7@\2\2\u016cX\3\2\2\2\u016d\u016e\7?\2\2\u016e\u016f"+
"\7?\2\2\u016fZ\3\2\2\2\u0170\u0171\7#\2\2\u0171\u0172\7?\2\2\u0172\\\3"+
"\2\2\2\u0173\u0174\7>\2\2\u0174\u0175\7?\2\2\u0175^\3\2\2\2\u0176\u0177"+
"\7@\2\2\u0177\u0178\7?\2\2\u0178`\3\2\2\2\u0179\u017a\7`\2\2\u017ab\3"+
"\2\2\2\u017b\u017c\7~\2\2\u017cd\3\2\2\2\u017d\u017e\7(\2\2\u017e\u017f"+
"\7(\2\2\u017ff\3\2\2\2\u0180\u0181\7~\2\2\u0181\u0182\7~\2\2\u0182h\3"+
"\2\2\2\u0183\u0184\7-\2\2\u0184\u0185\7?\2\2\u0185j\3\2\2\2\u0186\u0187"+
"\7/\2\2\u0187\u0188\7?\2\2\u0188l\3\2\2\2\u0189\u018a\7,\2\2\u018a\u018b"+
"\7?\2\2\u018bn\3\2\2\2\u018c\u018d\7\61\2\2\u018d\u018e\7?\2\2\u018ep"+
"\3\2\2\2\u018f\u0190\7\'\2\2\u0190\u0191\7?\2\2\u0191r\3\2\2\2\u0192\u0193"+
"\7>\2\2\u0193\u0194\7>\2\2\u0194\u0195\7?\2\2\u0195t\3\2\2\2\u0196\u0197"+
"\7@\2\2\u0197\u0198\7@\2\2\u0198\u0199\7?\2\2\u0199v\3\2\2\2\u019a\u019b"+
"\7(\2\2\u019b\u019c\7?\2\2\u019cx\3\2\2\2\u019d\u019e\7~\2\2\u019e\u019f"+
"\7?\2\2\u019fz\3\2\2\2\u01a0\u01a1\7`\2\2\u01a1\u01a2\7?\2\2\u01a2|\3"+
"\2\2\2\u01a3\u01a4\7m\2\2\u01a4\u01a5\7k\2\2\u01a5\u01a6\7e\2\2\u01a6"+
"\u01a7\7m\2\2\u01a7\u01a8\7c\2\2\u01a8\u01a9\7u\2\2\u01a9\u01aa\7o\2\2"+
"\u01aa~\3\2\2\2\u01ab\u01ac\7t\2\2\u01ac\u01ad\7g\2\2\u01ad\u01ae\7u\2"+
"\2\u01ae\u01af\7q\2\2\u01af\u01b0\7w\2\2\u01b0\u01b1\7t\2\2\u01b1\u01b2"+
"\7e\2\2\u01b2\u01b3\7g\2\2\u01b3\u0080\3\2\2\2\u01b4\u01b5\7w\2\2\u01b5"+
"\u01b6\7u\2\2\u01b6\u01b7\7g\2\2\u01b7\u01b8\7u\2\2\u01b8\u0082\3\2\2"+
"\2\u01b9\u01ba\7e\2\2\u01ba\u01bb\7n\2\2\u01bb\u01bc\7q\2\2\u01bc\u01bd"+
"\7d\2\2\u01bd\u01be\7d\2\2\u01be\u01bf\7g\2\2\u01bf\u01c0\7t\2\2\u01c0"+
"\u01c1\7u\2\2\u01c1\u0084\3\2\2\2\u01c2\u01c3\7d\2\2\u01c3\u01c4\7{\2"+
"\2\u01c4\u01c5\7v\2\2\u01c5\u01c6\7g\2\2\u01c6\u01c7\7u\2\2\u01c7\u0086"+
"\3\2\2\2\u01c8\u01c9\7e\2\2\u01c9\u01ca\7{\2\2\u01ca\u01cb\7e\2\2\u01cb"+
"\u01cc\7n\2\2\u01cc\u01cd\7g\2\2\u01cd\u01ce\7u\2\2\u01ce\u0088\3\2\2"+
"\2\u01cf\u01d0\7r\2\2\u01d0\u01d1\7e\2\2\u01d1\u008a\3\2\2\2\u01d2\u01d3"+
"\7\60\2\2\u01d3\u01d4\7d\2\2\u01d4\u01d5\7{\2\2\u01d5\u01d6\7v\2\2\u01d6"+
"\u01d7\7g\2\2\u01d7\u008c\3\2\2\2\u01d8\u01d9\7%\2\2\u01d9\u008e\3\2\2"+
"\2\u01da\u01db\7\60\2\2\u01db\u0090\3\2\2\2\u01dc\u01dd\7d\2\2\u01dd\u01de"+
"\7t\2\2\u01de\u02bb\7m\2\2\u01df\u01e0\7q\2\2\u01e0\u01e1\7t\2\2\u01e1"+
"\u02bb\7c\2\2\u01e2\u01e3\7m\2\2\u01e3\u01e4\7k\2\2\u01e4\u02bb\7n\2\2"+
"\u01e5\u01e6\7u\2\2\u01e6\u01e7\7n\2\2\u01e7\u02bb\7q\2\2\u01e8\u01e9"+
"\7p\2\2\u01e9\u01ea\7q\2\2\u01ea\u02bb\7r\2\2\u01eb\u01ec\7c\2\2\u01ec"+
"\u01ed\7u\2\2\u01ed\u02bb\7n\2\2\u01ee\u01ef\7r\2\2\u01ef\u01f0\7j\2\2"+
"\u01f0\u02bb\7r\2\2\u01f1\u01f2\7c\2\2\u01f2\u01f3\7p\2\2\u01f3\u02bb"+
"\7e\2\2\u01f4\u01f5\7d\2\2\u01f5\u01f6\7r\2\2\u01f6\u02bb\7n\2\2\u01f7"+
"\u01f8\7e\2\2\u01f8\u01f9\7n\2\2\u01f9\u02bb\7e\2\2\u01fa\u01fb\7l\2\2"+
"\u01fb\u01fc\7u\2\2\u01fc\u02bb\7t\2\2\u01fd\u01fe\7c\2\2\u01fe\u01ff"+
"\7p\2\2\u01ff\u02bb\7f\2\2\u0200\u0201\7t\2\2\u0201\u0202\7n\2\2\u0202"+
"\u02bb\7c\2\2\u0203\u0204\7d\2\2\u0204\u0205\7k\2\2\u0205\u02bb\7v\2\2"+
"\u0206\u0207\7t\2\2\u0207\u0208\7q\2\2\u0208\u02bb\7n\2\2\u0209\u020a"+
"\7r\2\2\u020a\u020b\7n\2\2\u020b\u02bb\7c\2\2\u020c\u020d\7r\2\2\u020d"+
"\u020e\7n\2\2\u020e\u02bb\7r\2\2\u020f\u0210\7d\2\2\u0210\u0211\7o\2\2"+
"\u0211\u02bb\7k\2\2\u0212\u0213\7u\2\2\u0213\u0214\7g\2\2\u0214\u02bb"+
"\7e\2\2\u0215\u0216\7t\2\2\u0216\u0217\7v\2\2\u0217\u02bb\7k\2\2\u0218"+
"\u0219\7g\2\2\u0219\u021a\7q\2\2\u021a\u02bb\7t\2\2\u021b\u021c\7u\2\2"+
"\u021c\u021d\7t\2\2\u021d\u02bb\7g\2\2\u021e\u021f\7n\2\2\u021f\u0220"+
"\7u\2\2\u0220\u02bb\7t\2\2\u0221\u0222\7r\2\2\u0222\u0223\7j\2\2\u0223"+
"\u02bb\7c\2\2\u0224\u0225\7c\2\2\u0225\u0226\7n\2\2\u0226\u02bb\7t\2\2"+
"\u0227\u0228\7l\2\2\u0228\u0229\7o\2\2\u0229\u02bb\7r\2\2\u022a\u022b"+
"\7d\2\2\u022b\u022c\7x\2\2\u022c\u02bb\7e\2\2\u022d\u022e\7e\2\2\u022e"+
"\u022f\7n\2\2\u022f\u02bb\7k\2\2\u0230\u0231\7t\2\2\u0231\u0232\7v\2\2"+
"\u0232\u02bb\7u\2\2\u0233\u0234\7c\2\2\u0234\u0235\7f\2\2\u0235\u02bb"+
"\7e\2\2\u0236\u0237\7t\2\2\u0237\u0238\7t\2\2\u0238\u02bb\7c\2\2\u0239"+
"\u023a\7d\2\2\u023a\u023b\7x\2\2\u023b\u02bb\7u\2\2\u023c\u023d\7u\2\2"+
"\u023d\u023e\7g\2\2\u023e\u02bb\7k\2\2\u023f\u0240\7u\2\2\u0240\u0241"+
"\7c\2\2\u0241\u02bb\7z\2\2\u0242\u0243\7u\2\2\u0243\u0244\7v\2\2\u0244"+
"\u02bb\7{\2\2\u0245\u0246\7u\2\2\u0246\u0247\7v\2\2\u0247\u02bb\7c\2\2"+
"\u0248\u0249\7u\2\2\u0249\u024a\7v\2\2\u024a\u02bb\7z\2\2\u024b\u024c"+
"\7f\2\2\u024c\u024d\7g\2\2\u024d\u02bb\7{\2\2\u024e\u024f\7v\2\2\u024f"+
"\u0250\7z\2\2\u0250\u02bb\7c\2\2\u0251\u0252\7z\2\2\u0252\u0253\7c\2\2"+
"\u0253\u02bb\7c\2\2\u0254\u0255\7d\2\2\u0255\u0256\7e\2\2\u0256\u02bb"+
"\7e\2\2\u0257\u0258\7c\2\2\u0258\u0259\7j\2\2\u0259\u02bb\7z\2\2\u025a"+
"\u025b\7v\2\2\u025b\u025c\7{\2\2\u025c\u02bb\7c\2\2\u025d\u025e\7v\2\2"+
"\u025e\u025f\7z\2\2\u025f\u02bb\7u\2\2\u0260\u0261\7v\2\2\u0261\u0262"+
"\7c\2\2\u0262\u02bb\7u\2\2\u0263\u0264\7u\2\2\u0264\u0265\7j\2\2\u0265"+
"\u02bb\7{\2\2\u0266\u0267\7u\2\2\u0267\u0268\7j\2\2\u0268\u02bb\7z\2\2"+
"\u0269\u026a\7n\2\2\u026a\u026b\7f\2\2\u026b\u02bb\7{\2\2\u026c\u026d"+
"\7n\2\2\u026d\u026e\7f\2\2\u026e\u02bb\7c\2\2\u026f\u0270\7n\2\2\u0270"+
"\u0271\7f\2\2\u0271\u02bb\7z\2\2\u0272\u0273\7n\2\2\u0273\u0274\7c\2\2"+
"\u0274\u02bb\7z\2\2\u0275\u0276\7v\2\2\u0276\u0277\7c\2\2\u0277\u02bb"+
"\7{\2\2\u0278\u0279\7v\2\2\u0279\u027a\7c\2\2\u027a\u02bb\7z\2\2\u027b"+
"\u027c\7d\2\2\u027c\u027d\7e\2\2\u027d\u02bb\7u\2\2\u027e\u027f\7e\2\2"+
"\u027f\u0280\7n\2\2\u0280\u02bb\7x\2\2\u0281\u0282\7v\2\2\u0282\u0283"+
"\7u\2\2\u0283\u02bb\7z\2\2\u0284\u0285\7n\2\2\u0285\u0286\7c\2\2\u0286"+
"\u02bb\7u\2\2\u0287\u0288\7e\2\2\u0288\u0289\7r\2\2\u0289\u02bb\7{\2\2"+
"\u028a\u028b\7e\2\2\u028b\u028c\7o\2\2\u028c\u02bb\7r\2\2\u028d\u028e"+
"\7e\2\2\u028e\u028f\7r\2\2\u028f\u02bb\7z\2\2\u0290\u0291\7f\2\2\u0291"+
"\u0292\7e\2\2\u0292\u02bb\7r\2\2\u0293\u0294\7f\2\2\u0294\u0295\7g\2\2"+
"\u0295\u02bb\7e\2\2\u0296\u0297\7k\2\2\u0297\u0298\7p\2\2\u0298\u02bb"+
"\7e\2\2\u0299\u029a\7c\2\2\u029a\u029b\7z\2\2\u029b\u02bb\7u\2\2\u029c"+
"\u029d\7d\2\2\u029d\u029e\7p\2\2\u029e\u02bb\7g\2\2\u029f\u02a0\7e\2\2"+
"\u02a0\u02a1\7n\2\2\u02a1\u02bb\7f\2\2\u02a2\u02a3\7u\2\2\u02a3\u02a4"+
"\7d\2\2\u02a4\u02bb\7e\2\2\u02a5\u02a6\7k\2\2\u02a6\u02a7\7u\2\2\u02a7"+
"\u02bb\7e\2\2\u02a8\u02a9\7k\2\2\u02a9\u02aa\7p\2\2\u02aa\u02bb\7z\2\2"+
"\u02ab\u02ac\7d\2\2\u02ac\u02ad\7g\2\2\u02ad\u02bb\7s\2\2\u02ae\u02af"+
"\7u\2\2\u02af\u02b0\7g\2\2\u02b0\u02bb\7f\2\2\u02b1\u02b2\7f\2\2\u02b2"+
"\u02b3\7g\2\2\u02b3\u02bb\7z\2\2\u02b4\u02b5\7k\2\2\u02b5\u02b6\7p\2\2"+
"\u02b6\u02bb\7{\2\2\u02b7\u02b8\7t\2\2\u02b8\u02b9\7q\2\2\u02b9\u02bb"+
"\7t\2\2\u02ba\u01dc\3\2\2\2\u02ba\u01df\3\2\2\2\u02ba\u01e2\3\2\2\2\u02ba"+
"\u01e5\3\2\2\2\u02ba\u01e8\3\2\2\2\u02ba\u01eb\3\2\2\2\u02ba\u01ee\3\2"+
"\2\2\u02ba\u01f1\3\2\2\2\u02ba\u01f4\3\2\2\2\u02ba\u01f7\3\2\2\2\u02ba"+
"\u01fa\3\2\2\2\u02ba\u01fd\3\2\2\2\u02ba\u0200\3\2\2\2\u02ba\u0203\3\2"+
"\2\2\u02ba\u0206\3\2\2\2\u02ba\u0209\3\2\2\2\u02ba\u020c\3\2\2\2\u02ba"+
"\u020f\3\2\2\2\u02ba\u0212\3\2\2\2\u02ba\u0215\3\2\2\2\u02ba\u0218\3\2"+
"\2\2\u02ba\u021b\3\2\2\2\u02ba\u021e\3\2\2\2\u02ba\u0221\3\2\2\2\u02ba"+
"\u0224\3\2\2\2\u02ba\u0227\3\2\2\2\u02ba\u022a\3\2\2\2\u02ba\u022d\3\2"+
"\2\2\u02ba\u0230\3\2\2\2\u02ba\u0233\3\2\2\2\u02ba\u0236\3\2\2\2\u02ba"+
"\u0239\3\2\2\2\u02ba\u023c\3\2\2\2\u02ba\u023f\3\2\2\2\u02ba\u0242\3\2"+
"\2\2\u02ba\u0245\3\2\2\2\u02ba\u0248\3\2\2\2\u02ba\u024b\3\2\2\2\u02ba"+
"\u024e\3\2\2\2\u02ba\u0251\3\2\2\2\u02ba\u0254\3\2\2\2\u02ba\u0257\3\2"+
"\2\2\u02ba\u025a\3\2\2\2\u02ba\u025d\3\2\2\2\u02ba\u0260\3\2\2\2\u02ba"+
"\u0263\3\2\2\2\u02ba\u0266\3\2\2\2\u02ba\u0269\3\2\2\2\u02ba\u026c\3\2"+
"\2\2\u02ba\u026f\3\2\2\2\u02ba\u0272\3\2\2\2\u02ba\u0275\3\2\2\2\u02ba"+
"\u0278\3\2\2\2\u02ba\u027b\3\2\2\2\u02ba\u027e\3\2\2\2\u02ba\u0281\3\2"+
"\2\2\u02ba\u0284\3\2\2\2\u02ba\u0287\3\2\2\2\u02ba\u028a\3\2\2\2\u02ba"+
"\u028d\3\2\2\2\u02ba\u0290\3\2\2\2\u02ba\u0293\3\2\2\2\u02ba\u0296\3\2"+
"\2\2\u02ba\u0299\3\2\2\2\u02ba\u029c\3\2\2\2\u02ba\u029f\3\2\2\2\u02ba"+
"\u02a2\3\2\2\2\u02ba\u02a5\3\2\2\2\u02ba\u02a8\3\2\2\2\u02ba\u02ab\3\2"+
"\2\2\u02ba\u02ae\3\2\2\2\u02ba\u02b1\3\2\2\2\u02ba\u02b4\3\2\2\2\u02ba"+
"\u02b7\3\2\2\2\u02bb\u0092\3\2\2\2\u02bc\u02bd\7}\2\2\u02bd\u02be\7}\2"+
"\2\u02be\u02c2\3\2\2\2\u02bf\u02c1\13\2\2\2\u02c0\u02bf\3\2\2\2\u02c1"+
"\u02c4\3\2\2\2\u02c2\u02c3\3\2\2\2\u02c2\u02c0\3\2\2\2\u02c3\u02c5\3\2"+
"\2\2\u02c4\u02c2\3\2\2\2\u02c5\u02c6\7\177\2\2\u02c6\u02c7\7\177\2\2\u02c7"+
"\u0094\3\2\2\2\u02c8\u02c9\7d\2\2\u02c9\u02ca\7{\2\2\u02ca\u02cb\7v\2"+
"\2\u02cb\u02de\7g\2\2\u02cc\u02cd\7y\2\2\u02cd\u02ce\7q\2\2\u02ce\u02cf"+
"\7t\2\2\u02cf\u02de\7f\2\2\u02d0\u02d1\7f\2\2\u02d1\u02d2\7y\2\2\u02d2"+
"\u02d3\7q\2\2\u02d3\u02d4\7t\2\2\u02d4\u02de\7f\2\2\u02d5\u02d6\7d\2\2"+
"\u02d6\u02d7\7q\2\2\u02d7\u02d8\7q\2\2\u02d8\u02de\7n\2\2\u02d9\u02da"+
"\7x\2\2\u02da\u02db\7q\2\2\u02db\u02dc\7k\2\2\u02dc\u02de\7f\2\2\u02dd"+
"\u02c8\3\2\2\2\u02dd\u02cc\3\2\2\2\u02dd\u02d0\3\2\2\2\u02dd\u02d5\3\2"+
"\2\2\u02dd\u02d9\3\2\2\2\u02de\u0096\3\2\2\2\u02df\u02e5\7$\2\2\u02e0"+
"\u02e1\7^\2\2\u02e1\u02e4\7$\2\2\u02e2\u02e4\n\2\2\2\u02e3\u02e0\3\2\2"+
"\2\u02e3\u02e2\3\2\2\2\u02e4\u02e7\3\2\2\2\u02e5\u02e3\3\2\2\2\u02e5\u02e6"+
"\3\2\2\2\u02e6\u02e8\3\2\2\2\u02e7\u02e5\3\2\2\2\u02e8\u02e9\7$\2\2\u02e9"+
"\u0098\3\2\2\2\u02ea\u02ee\7)\2\2\u02eb\u02ec\7^\2\2\u02ec\u02ef\7)\2"+
"\2\u02ed\u02ef\n\3\2\2\u02ee\u02eb\3\2\2\2\u02ee\u02ed\3\2\2\2\u02ef\u02f0"+
"\3\2\2\2\u02f0\u02f1\7)\2\2\u02f1\u009a\3\2\2\2\u02f2\u02f3\7v\2\2\u02f3"+
"\u02f4\7t\2\2\u02f4\u02f5\7w\2\2\u02f5\u02fc\7g\2\2\u02f6\u02f7\7h\2\2"+
"\u02f7\u02f8\7c\2\2\u02f8\u02f9\7n\2\2\u02f9\u02fa\7u\2\2\u02fa\u02fc"+
"\7g\2\2\u02fb\u02f2\3\2\2\2\u02fb\u02f6\3\2\2\2\u02fc\u009c\3\2\2\2\u02fd"+
"\u0300\5\u009fP\2\u02fe\u0300\5\u00a7T\2\u02ff\u02fd\3\2\2\2\u02ff\u02fe"+
"\3\2\2\2\u0300\u009e\3\2\2\2\u0301\u0305\5\u00a1Q\2\u0302\u0305\5\u00a3"+
"R\2\u0303\u0305\5\u00a5S\2\u0304\u0301\3\2\2\2\u0304\u0302\3\2\2\2\u0304"+
"\u0303\3\2\2\2\u0305\u00a0\3\2\2\2\u0306\u030c\7\'\2\2\u0307\u0308\7\62"+
"\2\2\u0308\u030c\7d\2\2\u0309\u030a\7\62\2\2\u030a\u030c\7D\2\2\u030b"+
"\u0306\3\2\2\2\u030b\u0307\3\2\2\2\u030b\u0309\3\2\2\2\u030c\u0310\3\2"+
"\2\2\u030d\u030f\5\u00afX\2\u030e\u030d\3\2\2\2\u030f\u0312\3\2\2\2\u0310"+
"\u030e\3\2\2\2\u0310\u0311\3\2\2\2\u0311\u0313\3\2\2\2\u0312\u0310\3\2"+
"\2\2\u0313\u0315\7\60\2\2\u0314\u0316\5\u00afX\2\u0315\u0314\3\2\2\2\u0316"+
"\u0317\3\2\2\2\u0317\u0315\3\2\2\2\u0317\u0318\3\2\2\2\u0318\u00a2\3\2"+
"\2\2\u0319\u031b\5\u00b1Y\2\u031a\u0319\3\2\2\2\u031b\u031e\3\2\2\2\u031c"+
"\u031a\3\2\2\2\u031c\u031d\3\2\2\2\u031d\u031f\3\2\2\2\u031e\u031c\3\2"+
"\2\2\u031f\u0321\7\60\2\2\u0320\u0322\5\u00b1Y\2\u0321\u0320\3\2\2\2\u0322"+
"\u0323\3\2\2\2\u0323\u0321\3\2\2\2\u0323\u0324\3\2\2\2\u0324\u00a4\3\2"+
"\2\2\u0325\u032b\7&\2\2\u0326\u0327\7\62\2\2\u0327\u032b\7z\2\2\u0328"+
"\u0329\7\62\2\2\u0329\u032b\7Z\2\2\u032a\u0325\3\2\2\2\u032a\u0326\3\2"+
"\2\2\u032a\u0328\3\2\2\2\u032b\u032f\3\2\2\2\u032c\u032e\5\u00b3Z\2\u032d"+
"\u032c\3\2\2\2\u032e\u0331\3\2\2\2\u032f\u032d\3\2\2\2\u032f\u0330\3\2"+
"\2\2\u0330\u0332\3\2\2\2\u0331\u032f\3\2\2\2\u0332\u0334\7\60\2\2\u0333"+
"\u0335\5\u00b3Z\2\u0334\u0333\3\2\2\2\u0335\u0336\3\2\2\2\u0336\u0334"+
"\3\2\2\2\u0336\u0337\3\2\2\2\u0337\u00a6\3\2\2\2\u0338\u033c\5\u00abV"+
"\2\u0339\u033c\5\u00adW\2\u033a\u033c\5\u00a9U\2\u033b\u0338\3\2\2\2\u033b"+
"\u0339\3\2\2\2\u033b\u033a\3\2\2\2\u033c\u00a8\3\2\2\2\u033d\u033e\7\62"+
"\2\2\u033e\u0340\t\4\2\2\u033f\u0341\5\u00afX\2\u0340\u033f\3\2\2\2\u0341"+
"\u0342\3\2\2\2\u0342\u0340\3\2\2\2\u0342\u0343\3\2\2\2\u0343\u034b\3\2"+
"\2\2\u0344\u0346\7\'\2\2\u0345\u0347\5\u00afX\2\u0346\u0345\3\2\2\2\u0347"+
"\u0348\3\2\2\2\u0348\u0346\3\2\2\2\u0348\u0349\3\2\2\2\u0349\u034b\3\2"+
"\2\2\u034a\u033d\3\2\2\2\u034a\u0344\3\2\2\2\u034b\u00aa\3\2\2\2\u034c"+
"\u034e\5\u00b1Y\2\u034d\u034c\3\2\2\2\u034e\u034f\3\2\2\2\u034f\u034d"+
"\3\2\2\2\u034f\u0350\3\2\2\2\u0350\u00ac\3\2\2\2\u0351\u0357\7&\2\2\u0352"+
"\u0353\7\62\2\2\u0353\u0357\7z\2\2\u0354\u0355\7\62\2\2\u0355\u0357\7"+
"Z\2\2\u0356\u0351\3\2\2\2\u0356\u0352\3\2\2\2\u0356\u0354\3\2\2\2\u0357"+
"\u0359\3\2\2\2\u0358\u035a\5\u00b3Z\2\u0359\u0358\3\2\2\2\u035a\u035b"+
"\3\2\2\2\u035b\u0359\3\2\2\2\u035b\u035c\3\2\2\2\u035c\u00ae\3\2\2\2\u035d"+
"\u035e\t\5\2\2\u035e\u00b0\3\2\2\2\u035f\u0360\t\6\2\2\u0360\u00b2\3\2"+
"\2\2\u0361\u0362\t\7\2\2\u0362\u00b4\3\2\2\2\u0363\u0367\5\u00b7\\\2\u0364"+
"\u0366\5\u00b9]\2\u0365\u0364\3\2\2\2\u0366\u0369\3\2\2\2\u0367\u0365"+
"\3\2\2\2\u0367\u0368\3\2\2\2\u0368\u00b6\3\2\2\2\u0369\u0367\3\2\2\2\u036a"+
"\u036b\t\b\2\2\u036b\u00b8\3\2\2\2\u036c\u036d\t\t\2\2\u036d\u00ba\3\2"+
"\2\2\u036e\u0372\7#\2\2\u036f\u0371\5\u00b9]\2\u0370\u036f\3\2\2\2\u0371"+
"\u0374\3\2\2\2\u0372\u0370\3\2\2\2\u0372\u0373\3\2\2\2\u0373\u0376\3\2"+
"\2\2\u0374\u0372\3\2\2\2\u0375\u0377\t\n\2\2\u0376\u0375\3\2\2\2\u0377"+
"\u0378\3\2\2\2\u0378\u0376\3\2\2\2\u0378\u0379\3\2\2\2\u0379\u00bc\3\2"+
"\2\2\u037a\u037c\t\13\2\2\u037b\u037a\3\2\2\2\u037c\u037d\3\2\2\2\u037d"+
"\u037b\3\2\2\2\u037d\u037e\3\2\2\2\u037e\u037f\3\2\2\2\u037f\u0380\b_"+
"\2\2\u0380\u00be\3\2\2\2\u0381\u0382\7\61\2\2\u0382\u0383\7\61\2\2\u0383"+
"\u0387\3\2\2\2\u0384\u0386\n\f\2\2\u0385\u0384\3\2\2\2\u0386\u0389\3\2"+
"\2\2\u0387\u0385\3\2\2\2\u0387\u0388\3\2\2\2\u0388\u038a\3\2\2\2\u0389"+
"\u0387\3\2\2\2\u038a\u038b\b`\3\2\u038b\u00c0\3\2\2\2\u038c\u038d\7\61"+
"\2\2\u038d\u038e\7,\2\2\u038e\u0392\3\2\2\2\u038f\u0391\13\2\2\2\u0390"+
"\u038f\3\2\2\2\u0391\u0394\3\2\2\2\u0392\u0393\3\2\2\2\u0392\u0390\3\2"+
"\2\2\u0393\u0395\3\2\2\2\u0394\u0392\3\2\2\2\u0395\u0396\7,\2\2\u0396"+
"\u0397\7\61\2\2\u0397\u0398\3\2\2\2\u0398\u0399\ba\3\2\u0399\u00c2\3\2"+
"\2\2!\2\u02ba\u02c2\u02dd\u02e3\u02e5\u02ee\u02fb\u02ff\u0304\u030b\u0310"+
"\u0317\u031c\u0323\u032a\u032f\u0336\u033b\u0342\u0348\u034a\u034f\u0356"+
"\u035b\u0367\u0372\u0378\u037d\u0387\u0392\4\2\3\2\2\4\2";
"`\t`\4a\ta\4b\tb\4c\tc\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\4\3\4\3\5"+
"\3\5\3\6\3\6\3\7\3\7\3\b\3\b\3\t\3\t\3\n\3\n\3\n\3\n\3\n\3\n\3\13\3\13"+
"\3\13\3\13\3\13\3\13\3\13\3\f\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r"+
"\3\r\3\r\3\r\3\r\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17"+
"\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\20\3\20\3\20\3\20\3\20\3\20\3\20"+
"\3\20\3\21\3\21\3\21\3\22\3\22\3\22\3\22\3\22\3\23\3\23\3\23\3\23\3\23"+
"\3\23\3\24\3\24\3\24\3\25\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\26\3\26"+
"\3\26\3\27\3\27\3\27\3\27\3\27\3\27\3\30\3\30\3\30\3\30\3\30\3\30\3\30"+
"\3\30\3\30\3\31\3\31\3\31\3\31\3\32\3\32\3\33\3\33\3\33\3\34\3\34\3\34"+
"\3\34\3\34\3\34\3\34\3\35\3\35\3\35\3\35\3\35\3\35\3\35\3\35\3\35\3\36"+
"\3\36\3\37\3\37\3 \3 \3!\3!\3!\3\"\3\"\3\"\3#\3#\3$\3$\3%\3%\3&\3&\3\'"+
"\3\'\3(\3(\3(\3)\3)\3)\3*\3*\3+\3+\3,\3,\3-\3-\3.\3.\3.\3/\3/\3/\3\60"+
"\3\60\3\60\3\61\3\61\3\61\3\62\3\62\3\63\3\63\3\64\3\64\3\64\3\65\3\65"+
"\3\65\3\66\3\66\3\67\3\67\3\67\38\38\38\39\39\39\3:\3:\3:\3;\3;\3;\3<"+
"\3<\3<\3<\3=\3=\3=\3=\3>\3>\3>\3?\3?\3?\3@\3@\3@\3A\3A\3A\3A\3A\3A\3A"+
"\3A\3B\3B\3B\3B\3B\3B\3B\3B\3B\3C\3C\3C\3C\3C\3D\3D\3D\3D\3D\3D\3D\3D"+
"\3D\3E\3E\3E\3E\3E\3E\3F\3F\3F\3F\3F\3F\3F\3G\3G\3G\3H\3H\3H\3H\3H\3H"+
"\3I\3I\3J\3J\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K"+
"\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K"+
"\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K"+
"\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K"+
"\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K"+
"\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K"+
"\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K"+
"\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K"+
"\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K"+
"\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\3K\5K\u02ca\nK"+
"\3L\3L\3L\3L\7L\u02d0\nL\fL\16L\u02d3\13L\3L\3L\3L\3M\3M\3M\3M\3M\3M\3"+
"M\3M\3M\3M\3M\3M\3M\3M\3M\3M\3M\3M\3M\3M\3M\3M\3M\3M\3M\3M\3M\3M\3M\3"+
"M\3M\3M\3M\3M\3M\3M\3M\5M\u02fd\nM\3N\3N\3N\3N\7N\u0303\nN\fN\16N\u0306"+
"\13N\3N\3N\3O\3O\3O\3O\5O\u030e\nO\3O\3O\3P\3P\3P\3P\3P\3P\3P\3P\3P\5"+
"P\u031b\nP\3Q\3Q\5Q\u031f\nQ\3R\3R\3R\5R\u0324\nR\3S\3S\3S\3S\3S\5S\u032b"+
"\nS\3S\7S\u032e\nS\fS\16S\u0331\13S\3S\3S\6S\u0335\nS\rS\16S\u0336\3T"+
"\7T\u033a\nT\fT\16T\u033d\13T\3T\3T\6T\u0341\nT\rT\16T\u0342\3U\3U\3U"+
"\3U\3U\5U\u034a\nU\3U\7U\u034d\nU\fU\16U\u0350\13U\3U\3U\6U\u0354\nU\r"+
"U\16U\u0355\3V\3V\3V\5V\u035b\nV\3W\3W\3W\6W\u0360\nW\rW\16W\u0361\3W"+
"\3W\6W\u0366\nW\rW\16W\u0367\5W\u036a\nW\3X\6X\u036d\nX\rX\16X\u036e\3"+
"Y\3Y\3Y\3Y\3Y\5Y\u0376\nY\3Y\6Y\u0379\nY\rY\16Y\u037a\3Z\3Z\3[\3[\3\\"+
"\3\\\3]\3]\7]\u0385\n]\f]\16]\u0388\13]\3^\3^\3_\3_\3`\3`\7`\u0390\n`"+
"\f`\16`\u0393\13`\3`\6`\u0396\n`\r`\16`\u0397\3a\6a\u039b\na\ra\16a\u039c"+
"\3a\3a\3b\3b\3b\3b\7b\u03a5\nb\fb\16b\u03a8\13b\3b\3b\3c\3c\3c\3c\7c\u03b0"+
"\nc\fc\16c\u03b3\13c\3c\3c\3c\3c\3c\4\u02d1\u03b1\2d\3\3\5\4\7\5\t\6\13"+
"\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'"+
"\25)\26+\27-\30/\31\61\32\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'"+
"M(O)Q*S+U,W-Y.[/]\60_\61a\62c\63e\64g\65i\66k\67m8o9q:s;u<w=y>{?}@\177"+
"A\u0081B\u0083C\u0085D\u0087E\u0089F\u008bG\u008dH\u008fI\u0091J\u0093"+
"K\u0095L\u0097M\u0099N\u009bO\u009dP\u009fQ\u00a1R\u00a3S\u00a5T\u00a7"+
"U\u00a9V\u00abW\u00adX\u00afY\u00b1Z\u00b3\2\u00b5\2\u00b7\2\u00b9[\u00bb"+
"\2\u00bd\2\u00bf\\\u00c1]\u00c3^\u00c5_\3\2\r\3\2$$\3\2))\4\2DDdd\3\2"+
"\62\63\3\2\62;\5\2\62;CHch\5\2C\\aac|\6\2\62;C\\aac|\4\2--//\6\2\13\f"+
"\17\17\"\"\u00a2\u00a2\4\2\f\f\17\17\2\u0425\2\3\3\2\2\2\2\5\3\2\2\2\2"+
"\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2"+
"\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2"+
"\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2\2"+
"\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61\3\2\2\2\2\63\3\2\2"+
"\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2"+
"\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2\2K\3\2\2\2\2"+
"M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2U\3\2\2\2\2W\3\2\2\2\2Y\3"+
"\2\2\2\2[\3\2\2\2\2]\3\2\2\2\2_\3\2\2\2\2a\3\2\2\2\2c\3\2\2\2\2e\3\2\2"+
"\2\2g\3\2\2\2\2i\3\2\2\2\2k\3\2\2\2\2m\3\2\2\2\2o\3\2\2\2\2q\3\2\2\2\2"+
"s\3\2\2\2\2u\3\2\2\2\2w\3\2\2\2\2y\3\2\2\2\2{\3\2\2\2\2}\3\2\2\2\2\177"+
"\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3\2\2\2\2\u0085\3\2\2\2\2\u0087\3\2\2"+
"\2\2\u0089\3\2\2\2\2\u008b\3\2\2\2\2\u008d\3\2\2\2\2\u008f\3\2\2\2\2\u0091"+
"\3\2\2\2\2\u0093\3\2\2\2\2\u0095\3\2\2\2\2\u0097\3\2\2\2\2\u0099\3\2\2"+
"\2\2\u009b\3\2\2\2\2\u009d\3\2\2\2\2\u009f\3\2\2\2\2\u00a1\3\2\2\2\2\u00a3"+
"\3\2\2\2\2\u00a5\3\2\2\2\2\u00a7\3\2\2\2\2\u00a9\3\2\2\2\2\u00ab\3\2\2"+
"\2\2\u00ad\3\2\2\2\2\u00af\3\2\2\2\2\u00b1\3\2\2\2\2\u00b9\3\2\2\2\2\u00bf"+
"\3\2\2\2\2\u00c1\3\2\2\2\2\u00c3\3\2\2\2\2\u00c5\3\2\2\2\3\u00c7\3\2\2"+
"\2\5\u00ce\3\2\2\2\7\u00d0\3\2\2\2\t\u00d2\3\2\2\2\13\u00d4\3\2\2\2\r"+
"\u00d6\3\2\2\2\17\u00d8\3\2\2\2\21\u00da\3\2\2\2\23\u00dc\3\2\2\2\25\u00e2"+
"\3\2\2\2\27\u00e9\3\2\2\2\31\u00ef\3\2\2\2\33\u00f8\3\2\2\2\35\u00ff\3"+
"\2\2\2\37\u0108\3\2\2\2!\u0112\3\2\2\2#\u0115\3\2\2\2%\u011a\3\2\2\2\'"+
"\u0120\3\2\2\2)\u0123\3\2\2\2+\u0127\3\2\2\2-\u012e\3\2\2\2/\u0134\3\2"+
"\2\2\61\u013d\3\2\2\2\63\u0141\3\2\2\2\65\u0143\3\2\2\2\67\u0146\3\2\2"+
"\29\u014d\3\2\2\2;\u0156\3\2\2\2=\u0158\3\2\2\2?\u015a\3\2\2\2A\u015c"+
"\3\2\2\2C\u015f\3\2\2\2E\u0162\3\2\2\2G\u0164\3\2\2\2I\u0166\3\2\2\2K"+
"\u0168\3\2\2\2M\u016a\3\2\2\2O\u016c\3\2\2\2Q\u016f\3\2\2\2S\u0172\3\2"+
"\2\2U\u0174\3\2\2\2W\u0176\3\2\2\2Y\u0178\3\2\2\2[\u017a\3\2\2\2]\u017d"+
"\3\2\2\2_\u0180\3\2\2\2a\u0183\3\2\2\2c\u0186\3\2\2\2e\u0188\3\2\2\2g"+
"\u018a\3\2\2\2i\u018d\3\2\2\2k\u0190\3\2\2\2m\u0192\3\2\2\2o\u0195\3\2"+
"\2\2q\u0198\3\2\2\2s\u019b\3\2\2\2u\u019e\3\2\2\2w\u01a1\3\2\2\2y\u01a5"+
"\3\2\2\2{\u01a9\3\2\2\2}\u01ac\3\2\2\2\177\u01af\3\2\2\2\u0081\u01b2\3"+
"\2\2\2\u0083\u01ba\3\2\2\2\u0085\u01c3\3\2\2\2\u0087\u01c8\3\2\2\2\u0089"+
"\u01d1\3\2\2\2\u008b\u01d7\3\2\2\2\u008d\u01de\3\2\2\2\u008f\u01e1\3\2"+
"\2\2\u0091\u01e7\3\2\2\2\u0093\u01e9\3\2\2\2\u0095\u02c9\3\2\2\2\u0097"+
"\u02cb\3\2\2\2\u0099\u02fc\3\2\2\2\u009b\u02fe\3\2\2\2\u009d\u0309\3\2"+
"\2\2\u009f\u031a\3\2\2\2\u00a1\u031e\3\2\2\2\u00a3\u0323\3\2\2\2\u00a5"+
"\u032a\3\2\2\2\u00a7\u033b\3\2\2\2\u00a9\u0349\3\2\2\2\u00ab\u035a\3\2"+
"\2\2\u00ad\u0369\3\2\2\2\u00af\u036c\3\2\2\2\u00b1\u0375\3\2\2\2\u00b3"+
"\u037c\3\2\2\2\u00b5\u037e\3\2\2\2\u00b7\u0380\3\2\2\2\u00b9\u0382\3\2"+
"\2\2\u00bb\u0389\3\2\2\2\u00bd\u038b\3\2\2\2\u00bf\u038d\3\2\2\2\u00c1"+
"\u039a\3\2\2\2\u00c3\u03a0\3\2\2\2\u00c5\u03ab\3\2\2\2\u00c7\u00c8\7k"+
"\2\2\u00c8\u00c9\7o\2\2\u00c9\u00ca\7r\2\2\u00ca\u00cb\7q\2\2\u00cb\u00cc"+
"\7t\2\2\u00cc\u00cd\7v\2\2\u00cd\4\3\2\2\2\u00ce\u00cf\7?\2\2\u00cf\6"+
"\3\2\2\2\u00d0\u00d1\7=\2\2\u00d1\b\3\2\2\2\u00d2\u00d3\7*\2\2\u00d3\n"+
"\3\2\2\2\u00d4\u00d5\7+\2\2\u00d5\f\3\2\2\2\u00d6\u00d7\7}\2\2\u00d7\16"+
"\3\2\2\2\u00d8\u00d9\7\177\2\2\u00d9\20\3\2\2\2\u00da\u00db\7.\2\2\u00db"+
"\22\3\2\2\2\u00dc\u00dd\7e\2\2\u00dd\u00de\7q\2\2\u00de\u00df\7p\2\2\u00df"+
"\u00e0\7u\2\2\u00e0\u00e1\7v\2\2\u00e1\24\3\2\2\2\u00e2\u00e3\7g\2\2\u00e3"+
"\u00e4\7z\2\2\u00e4\u00e5\7v\2\2\u00e5\u00e6\7g\2\2\u00e6\u00e7\7t\2\2"+
"\u00e7\u00e8\7p\2\2\u00e8\26\3\2\2\2\u00e9\u00ea\7c\2\2\u00ea\u00eb\7"+
"n\2\2\u00eb\u00ec\7k\2\2\u00ec\u00ed\7i\2\2\u00ed\u00ee\7p\2\2\u00ee\30"+
"\3\2\2\2\u00ef\u00f0\7t\2\2\u00f0\u00f1\7g\2\2\u00f1\u00f2\7i\2\2\u00f2"+
"\u00f3\7k\2\2\u00f3\u00f4\7u\2\2\u00f4\u00f5\7v\2\2\u00f5\u00f6\7g\2\2"+
"\u00f6\u00f7\7t\2\2\u00f7\32\3\2\2\2\u00f8\u00f9\7k\2\2\u00f9\u00fa\7"+
"p\2\2\u00fa\u00fb\7n\2\2\u00fb\u00fc\7k\2\2\u00fc\u00fd\7p\2\2\u00fd\u00fe"+
"\7g\2\2\u00fe\34\3\2\2\2\u00ff\u0100\7x\2\2\u0100\u0101\7q\2\2\u0101\u0102"+
"\7n\2\2\u0102\u0103\7c\2\2\u0103\u0104\7v\2\2\u0104\u0105\7k\2\2\u0105"+
"\u0106\7n\2\2\u0106\u0107\7g\2\2\u0107\36\3\2\2\2\u0108\u0109\7k\2\2\u0109"+
"\u010a\7p\2\2\u010a\u010b\7v\2\2\u010b\u010c\7g\2\2\u010c\u010d\7t\2\2"+
"\u010d\u010e\7t\2\2\u010e\u010f\7w\2\2\u010f\u0110\7r\2\2\u0110\u0111"+
"\7v\2\2\u0111 \3\2\2\2\u0112\u0113\7k\2\2\u0113\u0114\7h\2\2\u0114\"\3"+
"\2\2\2\u0115\u0116\7g\2\2\u0116\u0117\7n\2\2\u0117\u0118\7u\2\2\u0118"+
"\u0119\7g\2\2\u0119$\3\2\2\2\u011a\u011b\7y\2\2\u011b\u011c\7j\2\2\u011c"+
"\u011d\7k\2\2\u011d\u011e\7n\2\2\u011e\u011f\7g\2\2\u011f&\3\2\2\2\u0120"+
"\u0121\7f\2\2\u0121\u0122\7q\2\2\u0122(\3\2\2\2\u0123\u0124\7h\2\2\u0124"+
"\u0125\7q\2\2\u0125\u0126\7t\2\2\u0126*\3\2\2\2\u0127\u0128\7t\2\2\u0128"+
"\u0129\7g\2\2\u0129\u012a\7v\2\2\u012a\u012b\7w\2\2\u012b\u012c\7t\2\2"+
"\u012c\u012d\7p\2\2\u012d,\3\2\2\2\u012e\u012f\7d\2\2\u012f\u0130\7t\2"+
"\2\u0130\u0131\7g\2\2\u0131\u0132\7c\2\2\u0132\u0133\7m\2\2\u0133.\3\2"+
"\2\2\u0134\u0135\7e\2\2\u0135\u0136\7q\2\2\u0136\u0137\7p\2\2\u0137\u0138"+
"\7v\2\2\u0138\u0139\7k\2\2\u0139\u013a\7p\2\2\u013a\u013b\7w\2\2\u013b"+
"\u013c\7g\2\2\u013c\60\3\2\2\2\u013d\u013e\7c\2\2\u013e\u013f\7u\2\2\u013f"+
"\u0140\7o\2\2\u0140\62\3\2\2\2\u0141\u0142\7<\2\2\u0142\64\3\2\2\2\u0143"+
"\u0144\7\60\2\2\u0144\u0145\7\60\2\2\u0145\66\3\2\2\2\u0146\u0147\7u\2"+
"\2\u0147\u0148\7k\2\2\u0148\u0149\7i\2\2\u0149\u014a\7p\2\2\u014a\u014b"+
"\7g\2\2\u014b\u014c\7f\2\2\u014c8\3\2\2\2\u014d\u014e\7w\2\2\u014e\u014f"+
"\7p\2\2\u014f\u0150\7u\2\2\u0150\u0151\7k\2\2\u0151\u0152\7i\2\2\u0152"+
"\u0153\7p\2\2\u0153\u0154\7g\2\2\u0154\u0155\7f\2\2\u0155:\3\2\2\2\u0156"+
"\u0157\7,\2\2\u0157<\3\2\2\2\u0158\u0159\7]\2\2\u0159>\3\2\2\2\u015a\u015b"+
"\7_\2\2\u015b@\3\2\2\2\u015c\u015d\7/\2\2\u015d\u015e\7/\2\2\u015eB\3"+
"\2\2\2\u015f\u0160\7-\2\2\u0160\u0161\7-\2\2\u0161D\3\2\2\2\u0162\u0163"+
"\7-\2\2\u0163F\3\2\2\2\u0164\u0165\7/\2\2\u0165H\3\2\2\2\u0166\u0167\7"+
"#\2\2\u0167J\3\2\2\2\u0168\u0169\7(\2\2\u0169L\3\2\2\2\u016a\u016b\7\u0080"+
"\2\2\u016bN\3\2\2\2\u016c\u016d\7@\2\2\u016d\u016e\7@\2\2\u016eP\3\2\2"+
"\2\u016f\u0170\7>\2\2\u0170\u0171\7>\2\2\u0171R\3\2\2\2\u0172\u0173\7"+
"\61\2\2\u0173T\3\2\2\2\u0174\u0175\7\'\2\2\u0175V\3\2\2\2\u0176\u0177"+
"\7>\2\2\u0177X\3\2\2\2\u0178\u0179\7@\2\2\u0179Z\3\2\2\2\u017a\u017b\7"+
"?\2\2\u017b\u017c\7?\2\2\u017c\\\3\2\2\2\u017d\u017e\7#\2\2\u017e\u017f"+
"\7?\2\2\u017f^\3\2\2\2\u0180\u0181\7>\2\2\u0181\u0182\7?\2\2\u0182`\3"+
"\2\2\2\u0183\u0184\7@\2\2\u0184\u0185\7?\2\2\u0185b\3\2\2\2\u0186\u0187"+
"\7`\2\2\u0187d\3\2\2\2\u0188\u0189\7~\2\2\u0189f\3\2\2\2\u018a\u018b\7"+
"(\2\2\u018b\u018c\7(\2\2\u018ch\3\2\2\2\u018d\u018e\7~\2\2\u018e\u018f"+
"\7~\2\2\u018fj\3\2\2\2\u0190\u0191\7A\2\2\u0191l\3\2\2\2\u0192\u0193\7"+
"-\2\2\u0193\u0194\7?\2\2\u0194n\3\2\2\2\u0195\u0196\7/\2\2\u0196\u0197"+
"\7?\2\2\u0197p\3\2\2\2\u0198\u0199\7,\2\2\u0199\u019a\7?\2\2\u019ar\3"+
"\2\2\2\u019b\u019c\7\61\2\2\u019c\u019d\7?\2\2\u019dt\3\2\2\2\u019e\u019f"+
"\7\'\2\2\u019f\u01a0\7?\2\2\u01a0v\3\2\2\2\u01a1\u01a2\7>\2\2\u01a2\u01a3"+
"\7>\2\2\u01a3\u01a4\7?\2\2\u01a4x\3\2\2\2\u01a5\u01a6\7@\2\2\u01a6\u01a7"+
"\7@\2\2\u01a7\u01a8\7?\2\2\u01a8z\3\2\2\2\u01a9\u01aa\7(\2\2\u01aa\u01ab"+
"\7?\2\2\u01ab|\3\2\2\2\u01ac\u01ad\7~\2\2\u01ad\u01ae\7?\2\2\u01ae~\3"+
"\2\2\2\u01af\u01b0\7`\2\2\u01b0\u01b1\7?\2\2\u01b1\u0080\3\2\2\2\u01b2"+
"\u01b3\7m\2\2\u01b3\u01b4\7k\2\2\u01b4\u01b5\7e\2\2\u01b5\u01b6\7m\2\2"+
"\u01b6\u01b7\7c\2\2\u01b7\u01b8\7u\2\2\u01b8\u01b9\7o\2\2\u01b9\u0082"+
"\3\2\2\2\u01ba\u01bb\7t\2\2\u01bb\u01bc\7g\2\2\u01bc\u01bd\7u\2\2\u01bd"+
"\u01be\7q\2\2\u01be\u01bf\7w\2\2\u01bf\u01c0\7t\2\2\u01c0\u01c1\7e\2\2"+
"\u01c1\u01c2\7g\2\2\u01c2\u0084\3\2\2\2\u01c3\u01c4\7w\2\2\u01c4\u01c5"+
"\7u\2\2\u01c5\u01c6\7g\2\2\u01c6\u01c7\7u\2\2\u01c7\u0086\3\2\2\2\u01c8"+
"\u01c9\7e\2\2\u01c9\u01ca\7n\2\2\u01ca\u01cb\7q\2\2\u01cb\u01cc\7d\2\2"+
"\u01cc\u01cd\7d\2\2\u01cd\u01ce\7g\2\2\u01ce\u01cf\7t\2\2\u01cf\u01d0"+
"\7u\2\2\u01d0\u0088\3\2\2\2\u01d1\u01d2\7d\2\2\u01d2\u01d3\7{\2\2\u01d3"+
"\u01d4\7v\2\2\u01d4\u01d5\7g\2\2\u01d5\u01d6\7u\2\2\u01d6\u008a\3\2\2"+
"\2\u01d7\u01d8\7e\2\2\u01d8\u01d9\7{\2\2\u01d9\u01da\7e\2\2\u01da\u01db"+
"\7n\2\2\u01db\u01dc\7g\2\2\u01dc\u01dd\7u\2\2\u01dd\u008c\3\2\2\2\u01de"+
"\u01df\7r\2\2\u01df\u01e0\7e\2\2\u01e0\u008e\3\2\2\2\u01e1\u01e2\7\60"+
"\2\2\u01e2\u01e3\7d\2\2\u01e3\u01e4\7{\2\2\u01e4\u01e5\7v\2\2\u01e5\u01e6"+
"\7g\2\2\u01e6\u0090\3\2\2\2\u01e7\u01e8\7%\2\2\u01e8\u0092\3\2\2\2\u01e9"+
"\u01ea\7\60\2\2\u01ea\u0094\3\2\2\2\u01eb\u01ec\7d\2\2\u01ec\u01ed\7t"+
"\2\2\u01ed\u02ca\7m\2\2\u01ee\u01ef\7q\2\2\u01ef\u01f0\7t\2\2\u01f0\u02ca"+
"\7c\2\2\u01f1\u01f2\7m\2\2\u01f2\u01f3\7k\2\2\u01f3\u02ca\7n\2\2\u01f4"+
"\u01f5\7u\2\2\u01f5\u01f6\7n\2\2\u01f6\u02ca\7q\2\2\u01f7\u01f8\7p\2\2"+
"\u01f8\u01f9\7q\2\2\u01f9\u02ca\7r\2\2\u01fa\u01fb\7c\2\2\u01fb\u01fc"+
"\7u\2\2\u01fc\u02ca\7n\2\2\u01fd\u01fe\7r\2\2\u01fe\u01ff\7j\2\2\u01ff"+
"\u02ca\7r\2\2\u0200\u0201\7c\2\2\u0201\u0202\7p\2\2\u0202\u02ca\7e\2\2"+
"\u0203\u0204\7d\2\2\u0204\u0205\7r\2\2\u0205\u02ca\7n\2\2\u0206\u0207"+
"\7e\2\2\u0207\u0208\7n\2\2\u0208\u02ca\7e\2\2\u0209\u020a\7l\2\2\u020a"+
"\u020b\7u\2\2\u020b\u02ca\7t\2\2\u020c\u020d\7c\2\2\u020d\u020e\7p\2\2"+
"\u020e\u02ca\7f\2\2\u020f\u0210\7t\2\2\u0210\u0211\7n\2\2\u0211\u02ca"+
"\7c\2\2\u0212\u0213\7d\2\2\u0213\u0214\7k\2\2\u0214\u02ca\7v\2\2\u0215"+
"\u0216\7t\2\2\u0216\u0217\7q\2\2\u0217\u02ca\7n\2\2\u0218\u0219\7r\2\2"+
"\u0219\u021a\7n\2\2\u021a\u02ca\7c\2\2\u021b\u021c\7r\2\2\u021c\u021d"+
"\7n\2\2\u021d\u02ca\7r\2\2\u021e\u021f\7d\2\2\u021f\u0220\7o\2\2\u0220"+
"\u02ca\7k\2\2\u0221\u0222\7u\2\2\u0222\u0223\7g\2\2\u0223\u02ca\7e\2\2"+
"\u0224\u0225\7t\2\2\u0225\u0226\7v\2\2\u0226\u02ca\7k\2\2\u0227\u0228"+
"\7g\2\2\u0228\u0229\7q\2\2\u0229\u02ca\7t\2\2\u022a\u022b\7u\2\2\u022b"+
"\u022c\7t\2\2\u022c\u02ca\7g\2\2\u022d\u022e\7n\2\2\u022e\u022f\7u\2\2"+
"\u022f\u02ca\7t\2\2\u0230\u0231\7r\2\2\u0231\u0232\7j\2\2\u0232\u02ca"+
"\7c\2\2\u0233\u0234\7c\2\2\u0234\u0235\7n\2\2\u0235\u02ca\7t\2\2\u0236"+
"\u0237\7l\2\2\u0237\u0238\7o\2\2\u0238\u02ca\7r\2\2\u0239\u023a\7d\2\2"+
"\u023a\u023b\7x\2\2\u023b\u02ca\7e\2\2\u023c\u023d\7e\2\2\u023d\u023e"+
"\7n\2\2\u023e\u02ca\7k\2\2\u023f\u0240\7t\2\2\u0240\u0241\7v\2\2\u0241"+
"\u02ca\7u\2\2\u0242\u0243\7c\2\2\u0243\u0244\7f\2\2\u0244\u02ca\7e\2\2"+
"\u0245\u0246\7t\2\2\u0246\u0247\7t\2\2\u0247\u02ca\7c\2\2\u0248\u0249"+
"\7d\2\2\u0249\u024a\7x\2\2\u024a\u02ca\7u\2\2\u024b\u024c\7u\2\2\u024c"+
"\u024d\7g\2\2\u024d\u02ca\7k\2\2\u024e\u024f\7u\2\2\u024f\u0250\7c\2\2"+
"\u0250\u02ca\7z\2\2\u0251\u0252\7u\2\2\u0252\u0253\7v\2\2\u0253\u02ca"+
"\7{\2\2\u0254\u0255\7u\2\2\u0255\u0256\7v\2\2\u0256\u02ca\7c\2\2\u0257"+
"\u0258\7u\2\2\u0258\u0259\7v\2\2\u0259\u02ca\7z\2\2\u025a\u025b\7f\2\2"+
"\u025b\u025c\7g\2\2\u025c\u02ca\7{\2\2\u025d\u025e\7v\2\2\u025e\u025f"+
"\7z\2\2\u025f\u02ca\7c\2\2\u0260\u0261\7z\2\2\u0261\u0262\7c\2\2\u0262"+
"\u02ca\7c\2\2\u0263\u0264\7d\2\2\u0264\u0265\7e\2\2\u0265\u02ca\7e\2\2"+
"\u0266\u0267\7c\2\2\u0267\u0268\7j\2\2\u0268\u02ca\7z\2\2\u0269\u026a"+
"\7v\2\2\u026a\u026b\7{\2\2\u026b\u02ca\7c\2\2\u026c\u026d\7v\2\2\u026d"+
"\u026e\7z\2\2\u026e\u02ca\7u\2\2\u026f\u0270\7v\2\2\u0270\u0271\7c\2\2"+
"\u0271\u02ca\7u\2\2\u0272\u0273\7u\2\2\u0273\u0274\7j\2\2\u0274\u02ca"+
"\7{\2\2\u0275\u0276\7u\2\2\u0276\u0277\7j\2\2\u0277\u02ca\7z\2\2\u0278"+
"\u0279\7n\2\2\u0279\u027a\7f\2\2\u027a\u02ca\7{\2\2\u027b\u027c\7n\2\2"+
"\u027c\u027d\7f\2\2\u027d\u02ca\7c\2\2\u027e\u027f\7n\2\2\u027f\u0280"+
"\7f\2\2\u0280\u02ca\7z\2\2\u0281\u0282\7n\2\2\u0282\u0283\7c\2\2\u0283"+
"\u02ca\7z\2\2\u0284\u0285\7v\2\2\u0285\u0286\7c\2\2\u0286\u02ca\7{\2\2"+
"\u0287\u0288\7v\2\2\u0288\u0289\7c\2\2\u0289\u02ca\7z\2\2\u028a\u028b"+
"\7d\2\2\u028b\u028c\7e\2\2\u028c\u02ca\7u\2\2\u028d\u028e\7e\2\2\u028e"+
"\u028f\7n\2\2\u028f\u02ca\7x\2\2\u0290\u0291\7v\2\2\u0291\u0292\7u\2\2"+
"\u0292\u02ca\7z\2\2\u0293\u0294\7n\2\2\u0294\u0295\7c\2\2\u0295\u02ca"+
"\7u\2\2\u0296\u0297\7e\2\2\u0297\u0298\7r\2\2\u0298\u02ca\7{\2\2\u0299"+
"\u029a\7e\2\2\u029a\u029b\7o\2\2\u029b\u02ca\7r\2\2\u029c\u029d\7e\2\2"+
"\u029d\u029e\7r\2\2\u029e\u02ca\7z\2\2\u029f\u02a0\7f\2\2\u02a0\u02a1"+
"\7e\2\2\u02a1\u02ca\7r\2\2\u02a2\u02a3\7f\2\2\u02a3\u02a4\7g\2\2\u02a4"+
"\u02ca\7e\2\2\u02a5\u02a6\7k\2\2\u02a6\u02a7\7p\2\2\u02a7\u02ca\7e\2\2"+
"\u02a8\u02a9\7c\2\2\u02a9\u02aa\7z\2\2\u02aa\u02ca\7u\2\2\u02ab\u02ac"+
"\7d\2\2\u02ac\u02ad\7p\2\2\u02ad\u02ca\7g\2\2\u02ae\u02af\7e\2\2\u02af"+
"\u02b0\7n\2\2\u02b0\u02ca\7f\2\2\u02b1\u02b2\7u\2\2\u02b2\u02b3\7d\2\2"+
"\u02b3\u02ca\7e\2\2\u02b4\u02b5\7k\2\2\u02b5\u02b6\7u\2\2\u02b6\u02ca"+
"\7e\2\2\u02b7\u02b8\7k\2\2\u02b8\u02b9\7p\2\2\u02b9\u02ca\7z\2\2\u02ba"+
"\u02bb\7d\2\2\u02bb\u02bc\7g\2\2\u02bc\u02ca\7s\2\2\u02bd\u02be\7u\2\2"+
"\u02be\u02bf\7g\2\2\u02bf\u02ca\7f\2\2\u02c0\u02c1\7f\2\2\u02c1\u02c2"+
"\7g\2\2\u02c2\u02ca\7z\2\2\u02c3\u02c4\7k\2\2\u02c4\u02c5\7p\2\2\u02c5"+
"\u02ca\7{\2\2\u02c6\u02c7\7t\2\2\u02c7\u02c8\7q\2\2\u02c8\u02ca\7t\2\2"+
"\u02c9\u01eb\3\2\2\2\u02c9\u01ee\3\2\2\2\u02c9\u01f1\3\2\2\2\u02c9\u01f4"+
"\3\2\2\2\u02c9\u01f7\3\2\2\2\u02c9\u01fa\3\2\2\2\u02c9\u01fd\3\2\2\2\u02c9"+
"\u0200\3\2\2\2\u02c9\u0203\3\2\2\2\u02c9\u0206\3\2\2\2\u02c9\u0209\3\2"+
"\2\2\u02c9\u020c\3\2\2\2\u02c9\u020f\3\2\2\2\u02c9\u0212\3\2\2\2\u02c9"+
"\u0215\3\2\2\2\u02c9\u0218\3\2\2\2\u02c9\u021b\3\2\2\2\u02c9\u021e\3\2"+
"\2\2\u02c9\u0221\3\2\2\2\u02c9\u0224\3\2\2\2\u02c9\u0227\3\2\2\2\u02c9"+
"\u022a\3\2\2\2\u02c9\u022d\3\2\2\2\u02c9\u0230\3\2\2\2\u02c9\u0233\3\2"+
"\2\2\u02c9\u0236\3\2\2\2\u02c9\u0239\3\2\2\2\u02c9\u023c\3\2\2\2\u02c9"+
"\u023f\3\2\2\2\u02c9\u0242\3\2\2\2\u02c9\u0245\3\2\2\2\u02c9\u0248\3\2"+
"\2\2\u02c9\u024b\3\2\2\2\u02c9\u024e\3\2\2\2\u02c9\u0251\3\2\2\2\u02c9"+
"\u0254\3\2\2\2\u02c9\u0257\3\2\2\2\u02c9\u025a\3\2\2\2\u02c9\u025d\3\2"+
"\2\2\u02c9\u0260\3\2\2\2\u02c9\u0263\3\2\2\2\u02c9\u0266\3\2\2\2\u02c9"+
"\u0269\3\2\2\2\u02c9\u026c\3\2\2\2\u02c9\u026f\3\2\2\2\u02c9\u0272\3\2"+
"\2\2\u02c9\u0275\3\2\2\2\u02c9\u0278\3\2\2\2\u02c9\u027b\3\2\2\2\u02c9"+
"\u027e\3\2\2\2\u02c9\u0281\3\2\2\2\u02c9\u0284\3\2\2\2\u02c9\u0287\3\2"+
"\2\2\u02c9\u028a\3\2\2\2\u02c9\u028d\3\2\2\2\u02c9\u0290\3\2\2\2\u02c9"+
"\u0293\3\2\2\2\u02c9\u0296\3\2\2\2\u02c9\u0299\3\2\2\2\u02c9\u029c\3\2"+
"\2\2\u02c9\u029f\3\2\2\2\u02c9\u02a2\3\2\2\2\u02c9\u02a5\3\2\2\2\u02c9"+
"\u02a8\3\2\2\2\u02c9\u02ab\3\2\2\2\u02c9\u02ae\3\2\2\2\u02c9\u02b1\3\2"+
"\2\2\u02c9\u02b4\3\2\2\2\u02c9\u02b7\3\2\2\2\u02c9\u02ba\3\2\2\2\u02c9"+
"\u02bd\3\2\2\2\u02c9\u02c0\3\2\2\2\u02c9\u02c3\3\2\2\2\u02c9\u02c6\3\2"+
"\2\2\u02ca\u0096\3\2\2\2\u02cb\u02cc\7}\2\2\u02cc\u02cd\7}\2\2\u02cd\u02d1"+
"\3\2\2\2\u02ce\u02d0\13\2\2\2\u02cf\u02ce\3\2\2\2\u02d0\u02d3\3\2\2\2"+
"\u02d1\u02d2\3\2\2\2\u02d1\u02cf\3\2\2\2\u02d2\u02d4\3\2\2\2\u02d3\u02d1"+
"\3\2\2\2\u02d4\u02d5\7\177\2\2\u02d5\u02d6\7\177\2\2\u02d6\u0098\3\2\2"+
"\2\u02d7\u02d8\7d\2\2\u02d8\u02d9\7{\2\2\u02d9\u02da\7v\2\2\u02da\u02fd"+
"\7g\2\2\u02db\u02dc\7y\2\2\u02dc\u02dd\7q\2\2\u02dd\u02de\7t\2\2\u02de"+
"\u02fd\7f\2\2\u02df\u02e0\7f\2\2\u02e0\u02e1\7y\2\2\u02e1\u02e2\7q\2\2"+
"\u02e2\u02e3\7t\2\2\u02e3\u02fd\7f\2\2\u02e4\u02e5\7d\2\2\u02e5\u02e6"+
"\7q\2\2\u02e6\u02e7\7q\2\2\u02e7\u02fd\7n\2\2\u02e8\u02e9\7e\2\2\u02e9"+
"\u02ea\7j\2\2\u02ea\u02eb\7c\2\2\u02eb\u02fd\7t\2\2\u02ec\u02ed\7u\2\2"+
"\u02ed\u02ee\7j\2\2\u02ee\u02ef\7q\2\2\u02ef\u02f0\7t\2\2\u02f0\u02fd"+
"\7v\2\2\u02f1\u02f2\7k\2\2\u02f2\u02f3\7p\2\2\u02f3\u02fd\7v\2\2\u02f4"+
"\u02f5\7n\2\2\u02f5\u02f6\7q\2\2\u02f6\u02f7\7p\2\2\u02f7\u02fd\7i\2\2"+
"\u02f8\u02f9\7x\2\2\u02f9\u02fa\7q\2\2\u02fa\u02fb\7k\2\2\u02fb\u02fd"+
"\7f\2\2\u02fc\u02d7\3\2\2\2\u02fc\u02db\3\2\2\2\u02fc\u02df\3\2\2\2\u02fc"+
"\u02e4\3\2\2\2\u02fc\u02e8\3\2\2\2\u02fc\u02ec\3\2\2\2\u02fc\u02f1\3\2"+
"\2\2\u02fc\u02f4\3\2\2\2\u02fc\u02f8\3\2\2\2\u02fd\u009a\3\2\2\2\u02fe"+
"\u0304\7$\2\2\u02ff\u0300\7^\2\2\u0300\u0303\7$\2\2\u0301\u0303\n\2\2"+
"\2\u0302\u02ff\3\2\2\2\u0302\u0301\3\2\2\2\u0303\u0306\3\2\2\2\u0304\u0302"+
"\3\2\2\2\u0304\u0305\3\2\2\2\u0305\u0307\3\2\2\2\u0306\u0304\3\2\2\2\u0307"+
"\u0308\7$\2\2\u0308\u009c\3\2\2\2\u0309\u030d\7)\2\2\u030a\u030b\7^\2"+
"\2\u030b\u030e\7)\2\2\u030c\u030e\n\3\2\2\u030d\u030a\3\2\2\2\u030d\u030c"+
"\3\2\2\2\u030e\u030f\3\2\2\2\u030f\u0310\7)\2\2\u0310\u009e\3\2\2\2\u0311"+
"\u0312\7v\2\2\u0312\u0313\7t\2\2\u0313\u0314\7w\2\2\u0314\u031b\7g\2\2"+
"\u0315\u0316\7h\2\2\u0316\u0317\7c\2\2\u0317\u0318\7n\2\2\u0318\u0319"+
"\7u\2\2\u0319\u031b\7g\2\2\u031a\u0311\3\2\2\2\u031a\u0315\3\2\2\2\u031b"+
"\u00a0\3\2\2\2\u031c\u031f\5\u00a3R\2\u031d\u031f\5\u00abV\2\u031e\u031c"+
"\3\2\2\2\u031e\u031d\3\2\2\2\u031f\u00a2\3\2\2\2\u0320\u0324\5\u00a5S"+
"\2\u0321\u0324\5\u00a7T\2\u0322\u0324\5\u00a9U\2\u0323\u0320\3\2\2\2\u0323"+
"\u0321\3\2\2\2\u0323\u0322\3\2\2\2\u0324\u00a4\3\2\2\2\u0325\u032b\7\'"+
"\2\2\u0326\u0327\7\62\2\2\u0327\u032b\7d\2\2\u0328\u0329\7\62\2\2\u0329"+
"\u032b\7D\2\2\u032a\u0325\3\2\2\2\u032a\u0326\3\2\2\2\u032a\u0328\3\2"+
"\2\2\u032b\u032f\3\2\2\2\u032c\u032e\5\u00b3Z\2\u032d\u032c\3\2\2\2\u032e"+
"\u0331\3\2\2\2\u032f\u032d\3\2\2\2\u032f\u0330\3\2\2\2\u0330\u0332\3\2"+
"\2\2\u0331\u032f\3\2\2\2\u0332\u0334\7\60\2\2\u0333\u0335\5\u00b3Z\2\u0334"+
"\u0333\3\2\2\2\u0335\u0336\3\2\2\2\u0336\u0334\3\2\2\2\u0336\u0337\3\2"+
"\2\2\u0337\u00a6\3\2\2\2\u0338\u033a\5\u00b5[\2\u0339\u0338\3\2\2\2\u033a"+
"\u033d\3\2\2\2\u033b\u0339\3\2\2\2\u033b\u033c\3\2\2\2\u033c\u033e\3\2"+
"\2\2\u033d\u033b\3\2\2\2\u033e\u0340\7\60\2\2\u033f\u0341\5\u00b5[\2\u0340"+
"\u033f\3\2\2\2\u0341\u0342\3\2\2\2\u0342\u0340\3\2\2\2\u0342\u0343\3\2"+
"\2\2\u0343\u00a8\3\2\2\2\u0344\u034a\7&\2\2\u0345\u0346\7\62\2\2\u0346"+
"\u034a\7z\2\2\u0347\u0348\7\62\2\2\u0348\u034a\7Z\2\2\u0349\u0344\3\2"+
"\2\2\u0349\u0345\3\2\2\2\u0349\u0347\3\2\2\2\u034a\u034e\3\2\2\2\u034b"+
"\u034d\5\u00b7\\\2\u034c\u034b\3\2\2\2\u034d\u0350\3\2\2\2\u034e\u034c"+
"\3\2\2\2\u034e\u034f\3\2\2\2\u034f\u0351\3\2\2\2\u0350\u034e\3\2\2\2\u0351"+
"\u0353\7\60\2\2\u0352\u0354\5\u00b7\\\2\u0353\u0352\3\2\2\2\u0354\u0355"+
"\3\2\2\2\u0355\u0353\3\2\2\2\u0355\u0356\3\2\2\2\u0356\u00aa\3\2\2\2\u0357"+
"\u035b\5\u00afX\2\u0358\u035b\5\u00b1Y\2\u0359\u035b\5\u00adW\2\u035a"+
"\u0357\3\2\2\2\u035a\u0358\3\2\2\2\u035a\u0359\3\2\2\2\u035b\u00ac\3\2"+
"\2\2\u035c\u035d\7\62\2\2\u035d\u035f\t\4\2\2\u035e\u0360\5\u00b3Z\2\u035f"+
"\u035e\3\2\2\2\u0360\u0361\3\2\2\2\u0361\u035f\3\2\2\2\u0361\u0362\3\2"+
"\2\2\u0362\u036a\3\2\2\2\u0363\u0365\7\'\2\2\u0364\u0366\5\u00b3Z\2\u0365"+
"\u0364\3\2\2\2\u0366\u0367\3\2\2\2\u0367\u0365\3\2\2\2\u0367\u0368\3\2"+
"\2\2\u0368\u036a\3\2\2\2\u0369\u035c\3\2\2\2\u0369\u0363\3\2\2\2\u036a"+
"\u00ae\3\2\2\2\u036b\u036d\5\u00b5[\2\u036c\u036b\3\2\2\2\u036d\u036e"+
"\3\2\2\2\u036e\u036c\3\2\2\2\u036e\u036f\3\2\2\2\u036f\u00b0\3\2\2\2\u0370"+
"\u0376\7&\2\2\u0371\u0372\7\62\2\2\u0372\u0376\7z\2\2\u0373\u0374\7\62"+
"\2\2\u0374\u0376\7Z\2\2\u0375\u0370\3\2\2\2\u0375\u0371\3\2\2\2\u0375"+
"\u0373\3\2\2\2\u0376\u0378\3\2\2\2\u0377\u0379\5\u00b7\\\2\u0378\u0377"+
"\3\2\2\2\u0379\u037a\3\2\2\2\u037a\u0378\3\2\2\2\u037a\u037b\3\2\2\2\u037b"+
"\u00b2\3\2\2\2\u037c\u037d\t\5\2\2\u037d\u00b4\3\2\2\2\u037e\u037f\t\6"+
"\2\2\u037f\u00b6\3\2\2\2\u0380\u0381\t\7\2\2\u0381\u00b8\3\2\2\2\u0382"+
"\u0386\5\u00bb^\2\u0383\u0385\5\u00bd_\2\u0384\u0383\3\2\2\2\u0385\u0388"+
"\3\2\2\2\u0386\u0384\3\2\2\2\u0386\u0387\3\2\2\2\u0387\u00ba\3\2\2\2\u0388"+
"\u0386\3\2\2\2\u0389\u038a\t\b\2\2\u038a\u00bc\3\2\2\2\u038b\u038c\t\t"+
"\2\2\u038c\u00be\3\2\2\2\u038d\u0391\7#\2\2\u038e\u0390\5\u00bd_\2\u038f"+
"\u038e\3\2\2\2\u0390\u0393\3\2\2\2\u0391\u038f\3\2\2\2\u0391\u0392\3\2"+
"\2\2\u0392\u0395\3\2\2\2\u0393\u0391\3\2\2\2\u0394\u0396\t\n\2\2\u0395"+
"\u0394\3\2\2\2\u0396\u0397\3\2\2\2\u0397\u0395\3\2\2\2\u0397\u0398\3\2"+
"\2\2\u0398\u00c0\3\2\2\2\u0399\u039b\t\13\2\2\u039a\u0399\3\2\2\2\u039b"+
"\u039c\3\2\2\2\u039c\u039a\3\2\2\2\u039c\u039d\3\2\2\2\u039d\u039e\3\2"+
"\2\2\u039e\u039f\ba\2\2\u039f\u00c2\3\2\2\2\u03a0\u03a1\7\61\2\2\u03a1"+
"\u03a2\7\61\2\2\u03a2\u03a6\3\2\2\2\u03a3\u03a5\n\f\2\2\u03a4\u03a3\3"+
"\2\2\2\u03a5\u03a8\3\2\2\2\u03a6\u03a4\3\2\2\2\u03a6\u03a7\3\2\2\2\u03a7"+
"\u03a9\3\2\2\2\u03a8\u03a6\3\2\2\2\u03a9\u03aa\bb\3\2\u03aa\u00c4\3\2"+
"\2\2\u03ab\u03ac\7\61\2\2\u03ac\u03ad\7,\2\2\u03ad\u03b1\3\2\2\2\u03ae"+
"\u03b0\13\2\2\2\u03af\u03ae\3\2\2\2\u03b0\u03b3\3\2\2\2\u03b1\u03b2\3"+
"\2\2\2\u03b1\u03af\3\2\2\2\u03b2\u03b4\3\2\2\2\u03b3\u03b1\3\2\2\2\u03b4"+
"\u03b5\7,\2\2\u03b5\u03b6\7\61\2\2\u03b6\u03b7\3\2\2\2\u03b7\u03b8\bc"+
"\3\2\u03b8\u00c6\3\2\2\2!\2\u02c9\u02d1\u02fc\u0302\u0304\u030d\u031a"+
"\u031e\u0323\u032a\u032f\u0336\u033b\u0342\u0349\u034e\u0355\u035a\u0361"+
"\u0367\u0369\u036e\u0375\u037a\u0386\u0391\u0397\u039c\u03a6\u03b1\4\2"+
"\3\2\2\4\2";
public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
static {

View File

@ -69,26 +69,28 @@ T__67=68
T__68=69
T__69=70
T__70=71
MNEMONIC=72
KICKASM=73
SIMPLETYPE=74
STRING=75
CHAR=76
BOOLEAN=77
NUMBER=78
NUMFLOAT=79
BINFLOAT=80
DECFLOAT=81
HEXFLOAT=82
NUMINT=83
BININTEGER=84
DECINTEGER=85
HEXINTEGER=86
NAME=87
ASMREL=88
WS=89
COMMENT_LINE=90
COMMENT_BLOCK=91
T__71=72
T__72=73
MNEMONIC=74
KICKASM=75
SIMPLETYPE=76
STRING=77
CHAR=78
BOOLEAN=79
NUMBER=80
NUMFLOAT=81
BINFLOAT=82
DECFLOAT=83
HEXFLOAT=84
NUMINT=85
BININTEGER=86
DECINTEGER=87
HEXINTEGER=88
NAME=89
ASMREL=90
WS=91
COMMENT_LINE=92
COMMENT_BLOCK=93
'import'=1
'='=2
';'=3
@ -116,47 +118,49 @@ COMMENT_BLOCK=91
':'=25
'..'=26
'signed'=27
'*'=28
'['=29
']'=30
'--'=31
'++'=32
'+'=33
'-'=34
'!'=35
'&'=36
'~'=37
'>>'=38
'<<'=39
'/'=40
'%'=41
'<'=42
'>'=43
'=='=44
'!='=45
'<='=46
'>='=47
'^'=48
'|'=49
'&&'=50
'||'=51
'+='=52
'-='=53
'*='=54
'/='=55
'%='=56
'<<='=57
'>>='=58
'&='=59
'|='=60
'^='=61
'kickasm'=62
'resource'=63
'uses'=64
'clobbers'=65
'bytes'=66
'cycles'=67
'pc'=68
'.byte'=69
'#'=70
'.'=71
'unsigned'=28
'*'=29
'['=30
']'=31
'--'=32
'++'=33
'+'=34
'-'=35
'!'=36
'&'=37
'~'=38
'>>'=39
'<<'=40
'/'=41
'%'=42
'<'=43
'>'=44
'=='=45
'!='=46
'<='=47
'>='=48
'^'=49
'|'=50
'&&'=51
'||'=52
'?'=53
'+='=54
'-='=55
'*='=56
'/='=57
'%='=58
'<<='=59
'>>='=60
'&='=61
'|='=62
'^='=63
'kickasm'=64
'resource'=65
'uses'=66
'clobbers'=67
'bytes'=68
'cycles'=69
'pc'=70
'.byte'=71
'#'=72
'.'=73

View File

@ -1,4 +1,4 @@
// Generated from C:/c64/kickc/src/main/java/dk/camelot64/kickc/parser\KickC.g4 by ANTLR 4.7
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickC.g4 by ANTLR 4.7
package dk.camelot64.kickc.parser;
import org.antlr.v4.runtime.tree.ParseTreeListener;
@ -98,15 +98,29 @@ public interface KickCListener extends ParseTreeListener {
*/
void exitParameterListDecl(KickCParser.ParameterListDeclContext ctx);
/**
* Enter a parse tree produced by {@link KickCParser#parameterDecl}.
* Enter a parse tree produced by the {@code parameterDeclType}
* labeled alternative in {@link KickCParser#parameterDecl}.
* @param ctx the parse tree
*/
void enterParameterDecl(KickCParser.ParameterDeclContext ctx);
void enterParameterDeclType(KickCParser.ParameterDeclTypeContext ctx);
/**
* Exit a parse tree produced by {@link KickCParser#parameterDecl}.
* Exit a parse tree produced by the {@code parameterDeclType}
* labeled alternative in {@link KickCParser#parameterDecl}.
* @param ctx the parse tree
*/
void exitParameterDecl(KickCParser.ParameterDeclContext ctx);
void exitParameterDeclType(KickCParser.ParameterDeclTypeContext ctx);
/**
* Enter a parse tree produced by the {@code parameterDeclVoid}
* labeled alternative in {@link KickCParser#parameterDecl}.
* @param ctx the parse tree
*/
void enterParameterDeclVoid(KickCParser.ParameterDeclVoidContext ctx);
/**
* Exit a parse tree produced by the {@code parameterDeclVoid}
* labeled alternative in {@link KickCParser#parameterDecl}.
* @param ctx the parse tree
*/
void exitParameterDeclVoid(KickCParser.ParameterDeclVoidContext ctx);
/**
* Enter a parse tree produced by the {@code directiveConst}
* labeled alternative in {@link KickCParser#directive}.
@ -633,6 +647,18 @@ public interface KickCListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitExprId(KickCParser.ExprIdContext ctx);
/**
* Enter a parse tree produced by the {@code exprTernary}
* labeled alternative in {@link KickCParser#expr}.
* @param ctx the parse tree
*/
void enterExprTernary(KickCParser.ExprTernaryContext ctx);
/**
* Exit a parse tree produced by the {@code exprTernary}
* labeled alternative in {@link KickCParser#expr}.
* @param ctx the parse tree
*/
void exitExprTernary(KickCParser.ExprTernaryContext ctx);
/**
* Enter a parse tree produced by the {@code exprAssignment}
* labeled alternative in {@link KickCParser#expr}.

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
// Generated from C:/c64/kickc/src/main/java/dk/camelot64/kickc/parser\KickC.g4 by ANTLR 4.7
// Generated from /Users/jespergravgaard/c64/kickc/src/main/java/dk/camelot64/kickc/parser/KickC.g4 by ANTLR 4.7
package dk.camelot64.kickc.parser;
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
@ -65,11 +65,19 @@ public interface KickCVisitor<T> extends ParseTreeVisitor<T> {
*/
T visitParameterListDecl(KickCParser.ParameterListDeclContext ctx);
/**
* Visit a parse tree produced by {@link KickCParser#parameterDecl}.
* Visit a parse tree produced by the {@code parameterDeclType}
* labeled alternative in {@link KickCParser#parameterDecl}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitParameterDecl(KickCParser.ParameterDeclContext ctx);
T visitParameterDeclType(KickCParser.ParameterDeclTypeContext ctx);
/**
* Visit a parse tree produced by the {@code parameterDeclVoid}
* labeled alternative in {@link KickCParser#parameterDecl}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitParameterDeclVoid(KickCParser.ParameterDeclVoidContext ctx);
/**
* Visit a parse tree produced by the {@code directiveConst}
* labeled alternative in {@link KickCParser#directive}.
@ -377,6 +385,13 @@ public interface KickCVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitExprId(KickCParser.ExprIdContext ctx);
/**
* Visit a parse tree produced by the {@code exprTernary}
* labeled alternative in {@link KickCParser#expr}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitExprTernary(KickCParser.ExprTernaryContext ctx);
/**
* Visit a parse tree produced by the {@code exprAssignment}
* labeled alternative in {@link KickCParser#expr}.

View File

@ -150,14 +150,25 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
public List<Variable> visitParameterListDecl(KickCParser.ParameterListDeclContext ctx) {
ArrayList<Variable> parameterDecls = new ArrayList<>();
for(KickCParser.ParameterDeclContext parameterDeclCtx : ctx.parameterDecl()) {
Variable parameterDecl = (Variable) this.visit(parameterDeclCtx);
parameterDecls.add(parameterDecl);
Object parameterDecl = this.visit(parameterDeclCtx);
if(parameterDecl.equals(SymbolType.VOID)) {
if(ctx.parameterDecl().size() == 1) {
// A single void parameter decl - equals zero parameters
return new ArrayList<>();
} else {
throw new CompileError("Illegal void parameter." , new StatementSource(ctx));
}
} else if(parameterDecl instanceof Variable) {
parameterDecls.add((Variable) parameterDecl);
} else {
throw new CompileError("Unknown parameter " + ctx.getText(), new StatementSource(ctx));
}
}
return parameterDecls;
}
@Override
public Variable visitParameterDecl(KickCParser.ParameterDeclContext ctx) {
public Object visitParameterDeclType(KickCParser.ParameterDeclTypeContext ctx) {
SymbolType type = (SymbolType) this.visit(ctx.typeDecl());
VariableUnversioned param = new VariableUnversioned(ctx.NAME().getText(), getCurrentScope(), type);
// Add directives
@ -165,6 +176,14 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
return param;
}
@Override
public Object visitParameterDeclVoid(KickCParser.ParameterDeclVoidContext ctx) {
if(!SymbolType.VOID.getTypeName().equals(ctx.SIMPLETYPE().getText())) {
throw new CompileError("Illegal unnamed parameter " + ctx.SIMPLETYPE().getText(), new StatementSource(ctx));
}
return SymbolType.VOID;
}
@Override
public Object visitDeclKasm(KickCParser.DeclKasmContext ctx) {
String kasm = ctx.KICKASM().getText();
@ -594,10 +613,8 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
public Void visitStmtIfElse(KickCParser.StmtIfElseContext ctx) {
KickCParser.StmtContext ifStmt = ctx.stmt(0);
KickCParser.StmtContext elseStmt = ctx.stmt(1);
PrePostModifierHandler.addPreModifiers(this, ctx.expr());
RValue rValue = (RValue) this.visit(ctx.expr());
List<Comment> comments = ensureUnusedComments(getCommentsSymbol(ctx));
if(elseStmt == null) {
@ -649,7 +666,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
}
public Label getOrCreateBreakLabel() {
if(breakLabel==null) {
if(breakLabel == null) {
breakLabel = loopScope.addLabelIntermediate();
}
return breakLabel;
@ -664,7 +681,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
}
public Label getOrCreateContinueLabel() {
if(continueLabel==null) {
if(continueLabel == null) {
continueLabel = loopScope.addLabelIntermediate();
}
return continueLabel;
@ -827,14 +844,14 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
}
private void addLoopBreakLabel(Loop loop, ParserRuleContext ctx) {
if(loop.getBreakLabel()!=null) {
if(loop.getBreakLabel() != null) {
StatementLabel breakTarget = new StatementLabel(loop.getBreakLabel().getRef(), new StatementSource(ctx), Comment.NO_COMMENTS);
sequence.addStatement(breakTarget);
}
}
private void addLoopContinueLabel(Loop loop, ParserRuleContext ctx) {
if(loop.getContinueLabel()!=null) {
if(loop.getContinueLabel() != null) {
StatementLabel continueTarget = new StatementLabel(loop.getContinueLabel().getRef(), new StatementSource(ctx), Comment.NO_COMMENTS);
sequence.addStatement(continueTarget);
}
@ -1035,7 +1052,8 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
@Override
public SymbolType visitTypeSignedSimple(KickCParser.TypeSignedSimpleContext ctx) {
return SymbolType.get("signed " + ctx.SIMPLETYPE().getText());
String signedness = ctx.getChild(0).getText();
return SymbolType.get(signedness + " " + ctx.SIMPLETYPE().getText());
}
@Override
@ -1119,6 +1137,7 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
@Override
public Object visitExprCall(KickCParser.ExprCallContext ctx) {
List<RValue> parameters;
KickCParser.ParameterListContext parameterList = ctx.parameterList();
if(parameterList != null) {
@ -1128,7 +1147,15 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
}
VariableIntermediate tmpVar = getCurrentScope().addVariableIntermediate();
VariableRef tmpVarRef = tmpVar.getRef();
sequence.addStatement(new StatementCall(tmpVarRef, ctx.NAME().getText(), parameters, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx))));
String procedureName;
if(ctx.expr() instanceof KickCParser.ExprIdContext) {
procedureName = ctx.expr().getText();
sequence.addStatement(new StatementCall(tmpVarRef, procedureName, parameters, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx))));
} else {
RValue procedurePointer = (RValue) this.visit(ctx.expr());
sequence.addStatement(new StatementCallPointer(tmpVarRef, procedurePointer, parameters, new StatementSource(ctx), ensureUnusedComments(getCommentsSymbol(ctx))));
}
return tmpVarRef;
}
@ -1207,6 +1234,33 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
return tmpVarRef;
}
@Override
public RValue visitExprTernary(KickCParser.ExprTernaryContext ctx) {
RValue condValue = (RValue) this.visit(ctx.expr(0));
Label trueLabel = getCurrentScope().addLabelIntermediate();
Label falseLabel = getCurrentScope().addLabelIntermediate();
Label endJumpLabel = getCurrentScope().addLabelIntermediate();
sequence.addStatement(new StatementConditionalJump(condValue, trueLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
sequence.addStatement(new StatementLabel(falseLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
RValue falseValue = (RValue) this.visit(ctx.expr(2));
VariableRef falseVar = getCurrentScope().addVariableIntermediate().getRef();
sequence.addStatement(new StatementAssignment(falseVar, null, null, falseValue, new StatementSource(ctx), Comment.NO_COMMENTS));
sequence.addStatement(new StatementJump(endJumpLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
sequence.addStatement(new StatementLabel(trueLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
RValue trueValue = (RValue) this.visit(ctx.expr(1));
VariableRef trueVar = getCurrentScope().addVariableIntermediate().getRef();
sequence.addStatement(new StatementAssignment(trueVar, null, null, trueValue, new StatementSource(ctx), Comment.NO_COMMENTS));
sequence.addStatement(new StatementLabel(endJumpLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS));
StatementPhiBlock phiBlock = new StatementPhiBlock(Comment.NO_COMMENTS);
phiBlock.setSource(new StatementSource(ctx));
VariableRef finalVar = getCurrentScope().addVariableIntermediate().getRef();
StatementPhiBlock.PhiVariable phiVariable = phiBlock.addPhiVariable(finalVar);
phiVariable.setrValue(trueLabel.getRef(), trueVar);
phiVariable.setrValue(falseLabel.getRef(), falseVar);
sequence.addStatement(phiBlock);
return finalVar;
}
@Override
public Object visitExprPreMod(KickCParser.ExprPreModContext ctx) {
RValue child = (RValue) this.visit(ctx.expr());

View File

@ -1,14 +1,22 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.values.LabelRef;
import dk.camelot64.kickc.model.values.SymbolRef;
import dk.camelot64.kickc.model.values.VariableRef;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.VariableReferenceInfos;
import dk.camelot64.kickc.model.iterator.ProgramValue;
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementCall;
import dk.camelot64.kickc.model.statements.StatementConditionalJump;
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.values.LabelRef;
import dk.camelot64.kickc.model.values.SymbolRef;
import dk.camelot64.kickc.model.values.SymbolVariableRef;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
@ -29,7 +37,7 @@ public class Pass1AssertUsedVars extends Pass1Base {
VariableReferenceInfos referenceInfos = getProgram().getVariableReferenceInfos();
ControlFlowBlock beginBlock = getProgram().getGraph().getBlock(new LabelRef(SymbolRef.BEGIN_BLOCK_NAME));
assertUsedVars(beginBlock, referenceInfos, new LinkedHashSet<>(), new LinkedHashSet<>());
assertUsedVars(beginBlock, null, referenceInfos, new LinkedHashSet<>(), new LinkedHashSet<>());
getProgram().setVariableReferenceInfos(null);
new PassNStatementIndices(getProgram()).clearStatementIndices();
@ -42,16 +50,23 @@ public class Pass1AssertUsedVars extends Pass1Base {
* Follow the control flow of the graph recursively.
*
* @param block The block to examine
* @param predecessor The block jumping into this block (used for phi analysis)
* @param referenceInfos Information about assigned/used variables in statements
* @param defined Variables already assigned a value at the point of the first execution of the block
* @param visited Blocks already visited
*/
public void assertUsedVars(ControlFlowBlock block, VariableReferenceInfos referenceInfos, Collection<VariableRef> defined, Collection<LabelRef> visited) {
public void assertUsedVars(ControlFlowBlock block, LabelRef predecessor, VariableReferenceInfos referenceInfos, Collection<VariableRef> defined, Collection<LabelRef> visited) {
// If the block has a phi statement it is always examined (to not skip any of the predecessor checks)
assertUsedVarsPhi(block, predecessor, referenceInfos, defined);
// If we have already visited the block - skip it
if(visited.contains(block.getLabel())) {
return;
}
visited.add(block.getLabel());
// Examine all statements (except the potential PHI)
for(Statement statement : block.getStatements()) {
// PHI block has already been examined
if(statement instanceof StatementPhiBlock) continue;
Collection<VariableRef> used = referenceInfos.getUsedVars(statement);
for(VariableRef usedRef : used) {
if(!defined.contains(usedRef)) {
@ -70,16 +85,57 @@ public class Pass1AssertUsedVars extends Pass1Base {
}
ControlFlowBlock procedureStart = getProgram().getGraph().getBlock(call.getProcedure().getLabelRef());
assertUsedVars(procedureStart, referenceInfos, defined, visited);
assertUsedVars(procedureStart, block.getLabel(), referenceInfos, defined, visited);
} else if(statement instanceof StatementConditionalJump) {
StatementConditionalJump cond = (StatementConditionalJump) statement;
ControlFlowBlock jumpTo = getProgram().getGraph().getBlock(cond.getDestination());
assertUsedVars(jumpTo, referenceInfos, defined, visited);
assertUsedVars(jumpTo, block.getLabel(), referenceInfos, defined, visited);
}
}
ControlFlowBlock successor = getProgram().getGraph().getBlock(block.getDefaultSuccessor());
if(successor != null) {
assertUsedVars(successor, referenceInfos, defined, visited);
assertUsedVars(successor, block.getLabel(), referenceInfos, defined, visited);
}
}
/**
* Assert that all used vars have been assigned values before the use - in a PHI block.
*
* @param block The block to examine
* @param predecessor The block jumping into this block (used for phi analysis)
* @param referenceInfos Information about assigned/used variables in statements
* @param defined Variables already assigned a value at the point of the first execution of the block
* @param visited Blocks already visited
*/
private void assertUsedVarsPhi(ControlFlowBlock block, LabelRef predecessor, VariableReferenceInfos referenceInfos, Collection<VariableRef> defined) {
if(predecessor != null && block.hasPhiBlock()) {
StatementPhiBlock phiBlock = block.getPhiBlock();
ArrayList<SymbolVariableRef> used = new ArrayList<>();
for(StatementPhiBlock.PhiVariable phiVariable : phiBlock.getPhiVariables()) {
int i = 0;
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
if(predecessor.equals(phiRValue.getPredecessor())) {
ProgramValueIterator.execute(new ProgramValue.PhiValue(phiVariable, i), (programValue, currentStmt, stmtIt, currentBlock) -> {
if(programValue.get() instanceof SymbolVariableRef) {
if(!used.contains(programValue.get())) used.add((SymbolVariableRef) programValue.get());
}
}, phiBlock, null, block);
}
i++;
}
}
// Found used variables - check that they are defined
for(SymbolVariableRef usedRef : used) {
if(!defined.contains(usedRef)) {
throw new CompileError("Error! Variable used before being defined " + usedRef.toString(getProgram()) + " in " + phiBlock.toString(getProgram(), false), phiBlock.getSource());
}
}
// Add all variables fefined by the PHI block
Collection<VariableRef> defd = referenceInfos.getDefinedVars(phiBlock);
for(VariableRef definedRef : defd) {
defined.add(definedRef);
}
}
}

View File

@ -249,7 +249,8 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
List<ControlFlowBlock> predecessors = getGraph().getPredecessors(block);
Symbol symbol = getScope().getSymbol(block.getLabel());
if(symbol instanceof Procedure) {
if(((Procedure) symbol).getInterruptType()!=null) {
Procedure procedure = (Procedure) symbol;
if(procedure.getInterruptType()!=null || Pass2ConstantIdentification.isAddressOfUsed(procedure.getRef(), getProgram())) {
// Find all root-level predecessors to the main block
ControlFlowBlock mainBlock = getGraph().getBlock(new LabelRef(SymbolRef.MAIN_PROC_NAME));
List<ControlFlowBlock> mainPredecessors = getGraph().getPredecessors(mainBlock);

View File

@ -1,17 +1,17 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.values.LValue;
import dk.camelot64.kickc.model.values.ProcedureRef;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.VariableRef;
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
import dk.camelot64.kickc.model.values.*;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.statements.StatementCall;
import dk.camelot64.kickc.model.statements.StatementReturn;
import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.types.SymbolType;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** Pass that modifies a control flow graph to call procedures by passing parameters through registers */
@ -23,8 +23,25 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
this.program = program;
}
private Map<LabelRef, LabelRef> splitBlockMap = new LinkedHashMap<>();
public void generate() {
ControlFlowGraph generated = visitGraph(program.getGraph());
// Fix phi predecessors for any blocks has a split block as predecessor
for(ControlFlowBlock block : generated.getAllBlocks()) {
if(block.hasPhiBlock()) {
for(StatementPhiBlock.PhiVariable phiVariable : block.getPhiBlock().getPhiVariables()) {
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
LabelRef splitBlockNew = splitBlockMap.get(phiRValue.getPredecessor());
if(splitBlockNew !=null) {
phiRValue.setPredecessor(splitBlockNew);
}
}
}
}
}
program.setGraph(generated);
}
@ -62,7 +79,9 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
} else {
currentBlockScope = currentBlockSymbol.getScope();
}
splitCurrentBlock(currentBlockScope.addLabelIntermediate().getRef());
LabelRef splitBlockNewLabelRef = currentBlockScope.addLabelIntermediate().getRef();
splitCurrentBlock(splitBlockNewLabelRef);
splitBlockMap.put(this.getOrigBlock().getLabel(), splitBlockNewLabelRef);
if(!SymbolType.VOID.equals(procedure.getReturnType()) && origCall.getlValue() != null) {
addStatementToCurrentBlock(new StatementAssignment(origCall.getlValue(), procReturnVarRef, origCall.getSource(), Comment.NO_COMMENTS));
} else {

View File

@ -3,9 +3,7 @@ package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.statements.StatementCall;
import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.symbols.Scope;
import dk.camelot64.kickc.model.types.SymbolTypeInference;
@ -31,6 +29,14 @@ public class Pass1TypeInference extends Pass1Base {
} catch(CompileError e) {
throw new CompileError(e.getMessage(), statement.getSource());
}
} else if(statement instanceof StatementPhiBlock) {
for(StatementPhiBlock.PhiVariable phiVariable : ((StatementPhiBlock) statement).getPhiVariables()) {
try {
SymbolTypeInference.inferPhiVariable(getProgram(), phiVariable, false);
} catch(CompileError e) {
throw new CompileError(e.getMessage(), statement.getSource());
}
}
} else if(statement instanceof StatementCall) {
StatementCall call = (StatementCall) statement;
String procedureName = call.getProcedureName();
@ -44,7 +50,10 @@ public class Pass1TypeInference extends Pass1Base {
throw new CompileError("Wrong number of parameters in call. Expected " + procedure.getParameters().size() + ". " + statement.toString(), statement.getSource());
}
SymbolTypeInference.inferCallLValue(getProgram(), (StatementCall) statement, false);
} else if(statement instanceof StatementCallPointer) {
SymbolTypeInference.inferCallPointerLValue(getProgram(), (StatementCallPointer) statement, false);
}
}
}
return false;

View File

@ -1,10 +1,13 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.values.*;
import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
import dk.camelot64.kickc.model.symbols.ConstantVar;
import dk.camelot64.kickc.model.symbols.Symbol;
import dk.camelot64.kickc.model.symbols.VariableUnversioned;
import dk.camelot64.kickc.model.values.SymbolRef;
import java.util.Collection;
import java.util.HashSet;
/** Asserts that the symbols in the symbol table match exactly the symbols in the program */
@ -16,10 +19,17 @@ public class Pass2AssertSymbols extends Pass2SsaAssertion {
@Override
public void check() throws AssertionFailed {
SymbolFinder symbolFinder = new SymbolFinder(getScope());
symbolFinder.visitGraph(getGraph());
HashSet<Symbol> codeSymbols = symbolFinder.getSymbols();
// Check that all symbols found in the code is also oin the symbol tabel
HashSet<Symbol> codeSymbols = new HashSet<>();
ProgramValueIterator.execute(getGraph(), (programValue, currentStmt, stmtIt, currentBlock) -> {
if(programValue.get() instanceof SymbolRef) {
Symbol symbol = getScope().getSymbol((SymbolRef) programValue.get());
if(symbol != null)
codeSymbols.add(symbol);
}
});
// Check that all symbols found in the code is also in the symbol table
for(Symbol codeSymbol : codeSymbols) {
if(codeSymbol.getFullName().equals(SymbolRef.PROCEXIT_BLOCK_NAME)) continue;
Symbol tableSymbol = getScope().getSymbol(codeSymbol.getFullName());
@ -28,7 +38,7 @@ public class Pass2AssertSymbols extends Pass2SsaAssertion {
}
}
// Check that all symbols in the symbol table is also in the code
HashSet<Symbol> tableSymbols = getAllSymbols(getScope());
Collection<Symbol> tableSymbols = getScope().getAllSymbols(true);
for(Symbol tableSymbol : tableSymbols) {
if(tableSymbol instanceof VariableUnversioned) continue;
if(tableSymbol instanceof ConstantVar) continue;
@ -46,124 +56,4 @@ public class Pass2AssertSymbols extends Pass2SsaAssertion {
}
}
private HashSet<Symbol> getAllSymbols(Scope symbols) {
HashSet<Symbol> allSymbols = new HashSet<>();
for(Symbol symbol : symbols.getAllSymbols()) {
allSymbols.add(symbol);
if(symbol instanceof Scope) {
HashSet<Symbol> subSymbols = getAllSymbols((Scope) symbol);
allSymbols.addAll(subSymbols);
}
}
return allSymbols;
}
private static class SymbolFinder extends ControlFlowGraphBaseVisitor<Void> {
private ProgramScope programScope;
private HashSet<Symbol> symbols = new HashSet<>();
public SymbolFinder(ProgramScope programScope) {
this.programScope = programScope;
}
public HashSet<Symbol> getSymbols() {
return symbols;
}
private void addSymbol(Value symbol) {
if(symbol instanceof Symbol) {
symbols.add((Symbol) symbol);
} else if(symbol instanceof SymbolRef) {
addSymbol(programScope.getSymbol((SymbolRef) symbol));
} else if(symbol instanceof PointerDereferenceIndexed) {
addSymbol(((PointerDereferenceIndexed) symbol).getPointer());
addSymbol(((PointerDereferenceIndexed) symbol).getIndex());
} else if(symbol instanceof PointerDereferenceSimple) {
addSymbol(((PointerDereference) symbol).getPointer());
}
}
@Override
public Void visitBlock(ControlFlowBlock block) {
addSymbol(block.getLabel());
addSymbol(block.getDefaultSuccessor());
addSymbol(block.getConditionalSuccessor());
addSymbol(block.getCallSuccessor());
return super.visitBlock(block);
}
@Override
public Void visitProcedureBegin(StatementProcedureBegin procedureBegin) {
ProcedureRef procedureRef = procedureBegin.getProcedure();
Procedure procedure = programScope.getProcedure(procedureRef);
symbols.add(procedure);
return super.visitProcedureBegin(procedureBegin);
}
@Override
public Void visitProcedureEnd(StatementProcedureEnd procedureEnd) {
ProcedureRef procedureRef = procedureEnd.getProcedure();
Procedure procedure = programScope.getProcedure(procedureRef);
symbols.add(procedure);
return super.visitProcedureEnd(procedureEnd);
}
@Override
public Void visitReturn(StatementReturn aReturn) {
addSymbol(aReturn.getValue());
return super.visitReturn(aReturn);
}
@Override
public Void visitConditionalJump(StatementConditionalJump conditionalJump) {
addSymbol(conditionalJump.getrValue1());
addSymbol(conditionalJump.getrValue2());
addSymbol(conditionalJump.getDestination());
return super.visitConditionalJump(conditionalJump);
}
@Override
public Void visitAssignment(StatementAssignment assignment) {
addSymbol(assignment.getlValue());
addSymbol(assignment.getrValue1());
addSymbol(assignment.getrValue2());
return super.visitAssignment(assignment);
}
@Override
public Void visitJump(StatementJump jump) {
addSymbol(jump.getDestination());
return super.visitJump(jump);
}
@Override
public Void visitJumpTarget(StatementLabel jumpTarget) {
addSymbol(jumpTarget.getLabel());
return super.visitJumpTarget(jumpTarget);
}
@Override
public Void visitCall(StatementCall call) {
addSymbol(call.getlValue());
addSymbol(call.getProcedure());
if(call.getParameters() != null) {
for(RValue param : call.getParameters()) {
addSymbol(param);
}
}
return super.visitCall(call);
}
@Override
public Void visitPhiBlock(StatementPhiBlock phi) {
for(StatementPhiBlock.PhiVariable phiVariable : phi.getPhiVariables()) {
addSymbol(phiVariable.getVariable());
for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
addSymbol(phiRValue.getrValue());
}
}
return super.visitPhiBlock(phi);
}
}
}

View File

@ -1,5 +1,6 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.ConstantNotLiteral;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.VariableReferenceInfos;
@ -129,6 +130,18 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
assignment.setrValue1(new ConstantBinary(const1, Operators.PLUS, consolidated));
getLog().append("Consolidated constant in assignment " + assignment.getlValue());
return true;
} else {
// Check if the constant is zero
try {
ConstantLiteral constantLiteral = ((ConstantValue) assignment.getrValue1()).calculateLiteral(getScope());
if(constantLiteral.getValue().equals(0L)) {
getLog().append("Removed zero-constant in assignment " + assignment.getlValue());
assignment.setrValue1(null);
assignment.setOperator(null);
}
} catch(ConstantNotLiteral e) {
// ignore
}
}
} else if(assignment.getrValue1() instanceof VariableRef && assignment.getrValue2() instanceof ConstantValue) {
VariableRef variable = (VariableRef) assignment.getrValue1();
@ -140,6 +153,20 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
// Handling of negative consolidated numbers?
getLog().append("Consolidated constant in assignment " + assignment.getlValue());
return true;
} else {
// Check if the constant is zero
try {
ConstantLiteral constantLiteral = ((ConstantValue) assignment.getrValue2()).calculateLiteral(getScope());
if(constantLiteral.getValue().equals(0L)) {
getLog().append("Removed zero-constant in assignment " + assignment.getlValue());
assignment.setrValue2(assignment.getrValue1());
assignment.setOperator(null);
assignment.setrValue1(null);
}
} catch(ConstantNotLiteral e) {
// ignore
}
}
}
return false;

View File

@ -0,0 +1,96 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementCall;
import dk.camelot64.kickc.model.statements.StatementCallPointer;
import dk.camelot64.kickc.model.symbols.ConstantVar;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypePointer;
import dk.camelot64.kickc.model.types.SymbolTypeProcedure;
import dk.camelot64.kickc.model.values.*;
import java.util.ListIterator;
/** Pass that identified indirect calls to constant function pointers */
public class Pass2ConstantCallPointerIdentification extends Pass2SsaOptimization {
public Pass2ConstantCallPointerIdentification(Program program) {
super(program);
}
@Override
public boolean step() {
boolean optimized = false;
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
ListIterator<Statement> statementsIt = block.getStatements().listIterator();
while(statementsIt.hasNext()) {
Statement statement = statementsIt.next();
if(statement instanceof StatementCallPointer) {
StatementCallPointer callPointer = (StatementCallPointer) statement;
RValue procedure = callPointer.getProcedure();
if(procedure instanceof PointerDereferenceSimple) {
RValue pointer = ((PointerDereferenceSimple) procedure).getPointer();
ProcedureRef constProcedureRef = findConstProcedure(pointer);
if(constProcedureRef != null) {
replacePointerCall(callPointer, constProcedureRef, statementsIt, block);
optimized = true;
}
} else if(procedure instanceof ConstantRef) {
ConstantVar procedureVariable = getScope().getConstant((ConstantRef) procedure);
SymbolType procedureVariableType = procedureVariable.getType();
if(procedureVariableType instanceof SymbolTypePointer) {
if(((SymbolTypePointer) procedureVariableType).getElementType() instanceof SymbolTypeProcedure) {
ProcedureRef constProcedureRef = findConstProcedure(procedure);
if(constProcedureRef != null) {
replacePointerCall(callPointer, constProcedureRef, statementsIt, block);
optimized = true;
}
}
}
}
}
}
}
return optimized;
}
/**
* Replace a pointer-based call to a constant procedure with a classic procedure call
* @param callPointer The call to replace
* @param constProcedureRef The constant procedure pointed to
* @param statementsIt The statement iterator currently pointing to the pointer-based call
* @param block The block containing the call
*/
private void replacePointerCall(StatementCallPointer callPointer, ProcedureRef constProcedureRef, ListIterator<Statement> statementsIt, ControlFlowBlock block) {
statementsIt.remove();
StatementCall call = new StatementCall(callPointer.getlValue(), constProcedureRef.getFullName(), callPointer.getParameters(), callPointer.getSource(), callPointer.getComments());
call.setProcedure(constProcedureRef);
call.setIndex(callPointer.getIndex());
block.setCallSuccessor(constProcedureRef.getLabelRef());
statementsIt.add(call);
getLog().append("Replacing constant pointer function " + call.toString(getProgram(), false));
}
/**
* Examine whither the passed RValue represents a constant procedure pointer.
* If it does returns the procedure pointed to
*
* @param procedurePointer The potential procedure pointer
* @return The procedure pointed to
*/
private ProcedureRef findConstProcedure(RValue procedurePointer) {
if(procedurePointer instanceof ConstantRef) {
ConstantVar constant = getScope().getConstant((ConstantRef) procedurePointer);
return findConstProcedure(constant.getValue());
} else if(procedurePointer instanceof ConstantSymbolPointer) {
ConstantSymbolPointer pointer = (ConstantSymbolPointer) procedurePointer;
if(pointer.getToSymbol() instanceof ProcedureRef) {
return (ProcedureRef) pointer.getToSymbol();
}
}
return null;
}
}

View File

@ -45,13 +45,26 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
for(VariableRef constRef : constVars) {
Variable variable = getProgram().getScope().getVariable(constRef);
ConstantVariableValue constVarVal = constants.get(constRef);
// Weed out all variables that are affected by the address-of operator
if(isAddressOfUsed(constRef, getProgram())) {
// If the assignment has an operator then replace it with the single constant value
if(constVarVal.getAssignment() instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) constVarVal.getAssignment();
if(assignment.getOperator()!=null) {
getLog().append("Constant right-side identified " + assignment.toString(getProgram(), false));
assignment.setOperator(null);
assignment.setrValue1(null);
assignment.setrValue2(constVarVal.getConstantValue());
}
}
// But do not remove the variable
constants.remove(constRef);
continue;
}
ConstantVariableValue constVarVal = constants.get(constRef);
Scope constScope = variable.getScope();
ConstantValue constVal = constVarVal.getConstantValue();
@ -80,7 +93,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
constVal);
constantVar.setDeclaredAlignment(variable.getDeclaredAlignment());
constantVar.setDeclaredRegister(variable.getDeclaredRegister());
if(variable.getComments().size()>0) {
if(variable.getComments().size() > 0) {
constantVar.setComments(variable.getComments());
} else {
constantVar.setComments(constVarVal.getAssignment().getComments());
@ -111,7 +124,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
/**
* The statement that assigns the variable its value (the assignment will be removed at the end).
* Either a {@link StatementAssignment} or a {@link StatementPhiBlock}.
* */
*/
private Statement assignment;
public ConstantVariableValue(VariableRef variableRef, ConstantValue constantValue, Statement assignment) {
@ -182,83 +195,85 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
// Volatile variables cannot be constant
return;
}
if(assignment.getrValue1() == null && getConstant(assignment.getrValue2()) != null) {
if(assignment.getOperator() == null) {
// Constant assignment
ConstantValue constant = getConstant(assignment.getrValue2());
if(constant != null) {
constants.put(variable, new ConstantVariableValue(variable, constant, assignment));
}
} else {
// Constant unary expression
ConstantValue constant = createUnary(
(OperatorUnary) assignment.getOperator(),
getConstant(assignment.getrValue2())
);
if(constant != null) {
constants.put(variable, new ConstantVariableValue(variable, constant, assignment));
}
}
} else if(getConstant(assignment.getrValue1()) != null && getConstant(assignment.getrValue2()) != null) {
// Constant binary expression
ConstantValue constant = createBinary(
getConstant(assignment.getrValue1()),
(OperatorBinary) assignment.getOperator(),
getConstant(assignment.getrValue2()),
getScope());
if(constant != null) {
constants.put(variable, new ConstantVariableValue(variable, constant, assignment));
}
} else if(assignment.getrValue2() instanceof ValueList && assignment.getOperator() == null && assignment.getrValue1() == null) {
// A candidate for a constant list - examine to confirm
Variable lVariable = getScope().getVariable((VariableRef) lValue);
if(lVariable.getType() instanceof SymbolTypeArray) {
ValueList valueList = (ValueList) assignment.getrValue2();
List<RValue> values = valueList.getList();
boolean allConstant = true;
// Type of the elements of the list (deducted from the type of all elements)
SymbolType listType = null;
List<ConstantValue> elements = new ArrayList<>();
for(RValue elmValue : values) {
if(elmValue instanceof ConstantValue) {
ConstantValue constantValue = (ConstantValue) elmValue;
SymbolType elmType = constantValue.getType(getScope());
if(listType == null) {
listType = elmType;
} else {
if(!SymbolTypeInference.typeMatch(listType, elmType)) {
SymbolType intersectType = SymbolTypeInference.intersectTypes(listType, elmType);
if(intersectType == null) {
// No overlap between list type and element type
throw new RuntimeException("Array type " + listType + " does not match element type" + elmType + ". Array: " + valueList.toString(getProgram()));
} else {
listType = intersectType;
}
}
}
elements.add(constantValue);
} else {
allConstant = false;
listType = null;
break;
}
}
if(allConstant && listType != null) {
// Constant list confirmed!
ConstantValue constant = new ConstantArrayList(elements, listType);
constants.put(variable, new ConstantVariableValue(variable, constant, assignment));
}
}
} else if(Operators.ADDRESS_OF.equals(assignment.getOperator()) && assignment.getrValue1() == null) {
// Constant address-of variable
if(assignment.getrValue2() instanceof SymbolRef) {
ConstantSymbolPointer constantSymbolPointer = new ConstantSymbolPointer((SymbolRef) assignment.getrValue2());
constants.put(variable, new ConstantVariableValue(variable, constantSymbolPointer, assignment));
}
ConstantValue constant = getConstantAssignmentValue(assignment, var.getType());
if(constant != null) {
constants.put(variable, new ConstantVariableValue(variable, constant, assignment));
}
}
}
/**
* Examine the right side of an assignment and if it is constant then return the constant value.
* @param assignment The assignment to examine
* @param lValueType The type of the lvalue
* @return The constant value if the right side is constant
*/
private ConstantValue getConstantAssignmentValue(StatementAssignment assignment, SymbolType lValueType) {
if(assignment.getrValue1() == null && getConstant(assignment.getrValue2()) != null) {
if(assignment.getOperator() == null) {
// Constant assignment
return getConstant(assignment.getrValue2());
} else {
// Constant unary expression
return createUnary(
(OperatorUnary) assignment.getOperator(),
getConstant(assignment.getrValue2())
);
}
} else if(getConstant(assignment.getrValue1()) != null && getConstant(assignment.getrValue2()) != null) {
// Constant binary expression
return createBinary(
getConstant(assignment.getrValue1()),
(OperatorBinary) assignment.getOperator(),
getConstant(assignment.getrValue2()),
getScope());
} else if(assignment.getrValue2() instanceof ValueList && assignment.getOperator() == null && assignment.getrValue1() == null) {
// A candidate for a constant list - examine to confirm
if(lValueType instanceof SymbolTypeArray) {
ValueList valueList = (ValueList) assignment.getrValue2();
List<RValue> values = valueList.getList();
boolean allConstant = true;
// Type of the elements of the list (deducted from the type of all elements)
SymbolType listType = null;
List<ConstantValue> elements = new ArrayList<>();
for(RValue elmValue : values) {
if(elmValue instanceof ConstantValue) {
ConstantValue constantValue = (ConstantValue) elmValue;
SymbolType elmType = constantValue.getType(getScope());
if(listType == null) {
listType = elmType;
} else {
if(!SymbolTypeInference.typeMatch(listType, elmType)) {
SymbolType intersectType = SymbolTypeInference.intersectTypes(listType, elmType);
if(intersectType == null) {
// No overlap between list type and element type
throw new RuntimeException("Array type " + listType + " does not match element type" + elmType + ". Array: " + valueList.toString(getProgram()));
} else {
listType = intersectType;
}
}
}
elements.add(constantValue);
} else {
allConstant = false;
listType = null;
break;
}
}
if(allConstant && listType != null) {
// Constant list confirmed!
return new ConstantArrayList(elements, listType);
}
}
} else if(Operators.ADDRESS_OF.equals(assignment.getOperator()) && assignment.getrValue1() == null) {
// Constant address-of variable
if(assignment.getrValue2() instanceof SymbolRef) {
return new ConstantSymbolPointer((SymbolRef) assignment.getrValue2());
}
}
return null;
}
/**
* If the rValue is a known constant return the constant value.
*

View File

@ -61,7 +61,7 @@ public class Pass3LiveRangesEffectiveAnalysis extends Pass2Base {
if(callPaths == null) {
callPaths = new LiveRangeVariablesEffective.CallPaths(procedureRef);
if(procedure.getInterruptType()!=null) {
if(procedure.getInterruptType()!=null || Pass2ConstantIdentification.isAddressOfUsed(procedureRef, getProgram())) {
// Interrupt is called outside procedure scope - create initial call-path.
ArrayList<CallGraph.CallBlock.Call> rootPath = new ArrayList<>();
ArrayList<VariableRef> rootAlive = new ArrayList<>();

View File

@ -51,7 +51,8 @@ public class Pass3PhiLifting {
Variable lValVar = program.getScope().getVariable(phiVariable.getVariable());
newVar = ((VariableVersion) lValVar).getVersionOf().createVersion();
} else {
throw new RuntimeException("Only versions! " + phiVariable.getVariable());
Variable lValVar = program.getScope().getVariable(phiVariable.getVariable());
newVar = lValVar.getScope().addVariableIntermediate();
}
Symbol phiLValue = programScope.getSymbol(phiVariable.getVariable());
newVar.setType(phiLValue.getType());

View File

@ -9,6 +9,7 @@ import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeArray;
import dk.camelot64.kickc.model.types.SymbolTypePointer;
import dk.camelot64.kickc.model.types.SymbolTypeProcedure;
import dk.camelot64.kickc.model.values.*;
import java.util.*;
@ -64,10 +65,7 @@ public class Pass4CodeGeneration {
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
if(!block.getScope().equals(currentScope)) {
// The current block is in a different scope. End the old scope.
if(!ScopeRef.ROOT.equals(currentScope)) {
addData(asm, currentScope);
asm.addScopeEnd();
}
generateScopeEnding(asm, currentScope);
currentScope = block.getScope();
asm.startSegment(currentScope, null, block.getLabel().getFullName());
// Add any procedure comments
@ -121,10 +119,7 @@ public class Pass4CodeGeneration {
}
}
}
if(!ScopeRef.ROOT.equals(currentScope)) {
addData(asm, currentScope);
asm.addScopeEnd();
}
generateScopeEnding(asm, currentScope);
addData(asm, ScopeRef.ROOT);
// Add all absolutely placed inline KickAsm
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
@ -143,10 +138,47 @@ public class Pass4CodeGeneration {
}
}
}
program.setAsm(asm);
}
/**
* ASM names of variables being used for indirect calls in the current scope (procedure).
* These will all be added as indirect JMP's at the end of the procedure scope.
*/
private List<String> indirectCallAsmNames = new ArrayList<>();
/**
* Generate the end of a scope
* @param asm The assembler program being generated
* @param currentScope The current scope, which is ending here
*/
private void generateScopeEnding(AsmProgram asm, ScopeRef currentScope) {
if(!ScopeRef.ROOT.equals(currentScope)) {
// Generate any indirect calls pending
for(String indirectCallAsmName : indirectCallAsmNames) {
asm.addLabel("bi_"+indirectCallAsmName);
asm.addInstruction("jmp", AsmAddressingMode.IND, indirectCallAsmName, false);
}
indirectCallAsmNames = new ArrayList<>();
addData(asm, currentScope);
asm.addScopeEnd();
}
}
/**
* Add an indirect call to the assembler program. Also queues ASM for the indirect jump to be added at the end of the block.
* @param asm The ASM program being built
* @param procedureVariable The variable containing the function pointer
* @param codeScopeRef The scope containing the code being generated. Used for adding scope to the name when needed (eg. line.x1 when referencing x1 variable inside line scope from outside line scope).
*/
private void generateIndirectCall(AsmProgram asm, Variable procedureVariable, ScopeRef codeScopeRef) {
String varAsmName = AsmFormat.getAsmParamName(procedureVariable, codeScopeRef);
indirectCallAsmNames.add(varAsmName);
asm.addInstruction("jsr", AsmAddressingMode.ABS, "bi_" + varAsmName, false);
}
/**
* Generate a comment that describes the procedure signature and parameter transfer
* @param asm The assembler program being generated
@ -362,6 +394,13 @@ public class Pass4CodeGeneration {
} else if(SymbolType.isDWord(elementType) || SymbolType.isSDWord(elementType)) {
asm.addDataNumeric(asmName.replace("#", "_").replace("$", "_"), AsmDataNumeric.Type.DWORD, asmElements);
added.add(asmName);
} else if(elementType instanceof SymbolTypePointer) {
if(((SymbolTypePointer) elementType).getElementType() instanceof SymbolTypeProcedure) {
asm.addDataNumeric(asmName.replace("#", "_").replace("$", "_"), AsmDataNumeric.Type.WORD, asmElements);
added.add(asmName);
} else {
throw new RuntimeException("Unhandled constant array element type " + constantArrayList.toString(program));
}
} else {
throw new RuntimeException("Unhandled constant array element type " + constantArrayList.toString(program));
}
@ -563,9 +602,49 @@ public class Pass4CodeGeneration {
if(statementKasm.getLocation() == null) {
addKickAsm(asm, statementKasm);
}
if(statementKasm.getDeclaredClobber()!=null) {
if(statementKasm.getDeclaredClobber() != null) {
asm.getCurrentSegment().setClobberOverwrite(statementKasm.getDeclaredClobber());
}
} else if(statement instanceof StatementCallPointer) {
StatementCallPointer callPointer = (StatementCallPointer) statement;
RValue procedure = callPointer.getProcedure();
boolean supported = false;
if(procedure instanceof PointerDereferenceSimple) {
RValue pointer = ((PointerDereferenceSimple) procedure).getPointer();
if(pointer instanceof ConstantValue) {
asm.addInstruction("jsr", AsmAddressingMode.ABS, AsmFormat.getAsmConstant(program, (ConstantValue) pointer, 99, block.getScope()), false);
supported = true;
} else if(pointer instanceof VariableRef) {
Variable variable = getScope().getVariable((VariableRef) pointer);
generateIndirectCall(asm, variable, block.getScope());
supported = true;
}
} else if(procedure instanceof VariableRef) {
Variable procedureVariable = getScope().getVariable((VariableRef) procedure);
SymbolType procedureVariableType = procedureVariable.getType();
if(procedureVariableType instanceof SymbolTypePointer) {
if(((SymbolTypePointer) procedureVariableType).getElementType() instanceof SymbolTypeProcedure) {
generateIndirectCall(asm, procedureVariable, block.getScope());
supported = true;
}
}
} else if(procedure instanceof ConstantRef) {
ConstantVar procedureVariable = getScope().getConstant((ConstantRef) procedure);
SymbolType procedureVariableType = procedureVariable.getType();
if(procedureVariableType instanceof SymbolTypePointer) {
if(((SymbolTypePointer) procedureVariableType).getElementType() instanceof SymbolTypeProcedure) {
String varAsmName = AsmFormat.getAsmParamName(procedureVariable, block.getScope());
asm.addInstruction("jsr", AsmAddressingMode.ABS, varAsmName,false);
supported = true;
}
}
}
if(supported) {
asm.getCurrentSegment().setClobberOverwrite(AsmClobber.CLOBBER_ALL);
}
if(!supported) {
throw new RuntimeException("Call Pointer not supported " + statement);
}
} else {
throw new RuntimeException("Statement not supported " + statement);
}
@ -573,27 +652,30 @@ public class Pass4CodeGeneration {
}
/**
* Generate ASM code for an ASM fragment instance ()
* Generate ASM code for an ASM fragment instance
* @param asm The ASM program to generate into
* @param asmFragmentInstanceSpecFactory The ASM fragment instance specification factory
*/
private void generateAsm(AsmProgram asm, AsmFragmentInstanceSpecFactory asmFragmentInstanceSpecFactory) {
String initialSignature = asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec().getSignature();
AsmFragmentInstanceSpec asmFragmentInstanceSpec = asmFragmentInstanceSpecFactory.getAsmFragmentInstanceSpec();
AsmFragmentInstance asmFragmentInstance = null;
StringBuffer fragmentVariationsTried = new StringBuffer();
while(asmFragmentInstance==null) {
try {
asmFragmentInstance = AsmFragmentTemplateSynthesizer.getFragmentInstance(asmFragmentInstanceSpec, program.getLog());
} catch(AsmFragmentTemplateSynthesizer.UnknownFragmentException e) {
// Unknown fragment - keep looking through alternative ASM fragment instance specs until we have tried them all
String signature = asmFragmentInstanceSpec.getSignature();
fragmentVariationsTried.append(signature).append(" ");
if(asmFragmentInstanceSpec.hasNextVariation()) {
String signature = asmFragmentInstanceSpec.getSignature();
asmFragmentInstanceSpec.nextVariation();
if(program.getLog().isVerboseFragmentLog()) {
program.getLog().append("Fragment not found "+signature+". Attempting another variation "+asmFragmentInstanceSpec.getSignature());
}
} else {
// No more variations available - fail with an error
throw e;
throw new AsmFragmentTemplateSynthesizer.UnknownFragmentException("Fragment not found "+initialSignature+". Attempted variations "+fragmentVariationsTried);
}
}
}

View File

@ -1,6 +1,7 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.symbols.VariableVersion;
import dk.camelot64.kickc.model.values.VariableRef;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.symbols.Variable;
@ -28,6 +29,28 @@ public class Pass4LiveRangeEquivalenceClassesFinalize extends Pass2Base {
getLog().append(liveRangeEquivalenceClass.toString());
}
// Add all versions of volatile variables to the same equivalence class
for(Variable variable : getSymbols().getAllVariables(true)) {
if(variable.isVersioned() && variable.isDeclaredVolatile()) {
// Found a volatile non-versioned variable
for(Variable otherVariable : variable.getScope().getAllVariables(false)) {
if(otherVariable.isVersioned()) {
if(((VariableVersion)otherVariable).getVersionOf().equals(((VariableVersion)variable).getVersionOf())) {
// They share the same main variable
LiveRangeEquivalenceClass varEC = liveRangeEquivalenceClassSet.getOrCreateEquivalenceClass(variable.getRef());
LiveRangeEquivalenceClass otherEC = liveRangeEquivalenceClassSet.getOrCreateEquivalenceClass(otherVariable.getRef());
if(!varEC.equals(otherEC)) {
getLog().append("Coalescing volatile variable equivalence classes " + varEC.toString() + " and " + otherEC.toString());
liveRangeEquivalenceClassSet.consolidate(varEC, otherEC);
}
}
}
}
}
}
// Add all other variables one by one to an available equivalence class - or create a new one
EquivalenceClassAdder equivalenceClassAdder = new EquivalenceClassAdder(liveRangeEquivalenceClassSet);
equivalenceClassAdder.visitGraph(getGraph());

View File

@ -1,10 +1,7 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.values.ConstantSymbolPointer;
import dk.camelot64.kickc.model.values.SymbolRef;
import dk.camelot64.kickc.model.values.VariableRef;
import dk.camelot64.kickc.model.symbols.ConstantVar;
import dk.camelot64.kickc.model.symbols.Variable;
import java.util.ArrayList;
@ -49,12 +46,12 @@ public class Pass4RegisterUpliftPotentialInitialize extends Pass2Base {
Registers.RegisterType registerType = defaultRegister.getType();
List<Registers.Register> potentials = new ArrayList<>();
potentials.add(defaultRegister);
if(registerType.equals(Registers.RegisterType.ZP_BYTE) && !varRefExtracted(equivalenceClass) &&!varVolatile(equivalenceClass)) {
if(registerType.equals(Registers.RegisterType.ZP_BYTE) && !isAddressOfUsed(equivalenceClass) &&!varVolatile(equivalenceClass)) {
potentials.add(Registers.getRegisterA());
potentials.add(Registers.getRegisterX());
potentials.add(Registers.getRegisterY());
}
if(registerType.equals(Registers.RegisterType.ZP_BOOL) && !varRefExtracted(equivalenceClass) &&!varVolatile(equivalenceClass)) {
if(registerType.equals(Registers.RegisterType.ZP_BOOL) && !isAddressOfUsed(equivalenceClass) &&!varVolatile(equivalenceClass)) {
potentials.add(Registers.getRegisterA());
}
registerPotentials.setPotentialRegisters(equivalenceClass, potentials);
@ -83,14 +80,10 @@ public class Pass4RegisterUpliftPotentialInitialize extends Pass2Base {
* @param equivalenceClass The equivalence class
* @return true if a variable reference is extracted
*/
private boolean varRefExtracted(LiveRangeEquivalenceClass equivalenceClass) {
Collection<ConstantVar> allConstants = getProgram().getScope().getAllConstants(true);
for(ConstantVar allConstant : allConstants) {
if(allConstant.getValue() instanceof ConstantSymbolPointer) {
SymbolRef toSym = ((ConstantSymbolPointer) allConstant.getValue()).getToSymbol();
if(equivalenceClass.getVariables().contains(toSym)) {
return true;
}
private boolean isAddressOfUsed(LiveRangeEquivalenceClass equivalenceClass) {
for(VariableRef variableRef : equivalenceClass.getVariables()) {
if(Pass2ConstantIdentification.isAddressOfUsed(variableRef, getProgram())) {
return true;
}
}
return false;

View File

@ -26,7 +26,7 @@ public class Pass4ZeroPageCoalesce extends Pass2Base {
public void coalesce() {
LinkedHashSet<String> unknownFragments = new LinkedHashSet<>();
LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet = getProgram().getLiveRangeEquivalenceClassSet();
Collection<ScopeRef> threads = getThreadHeads(getSymbols());
Collection<ScopeRef> threads = getThreadHeads(getProgram());
boolean change;
do {
change = coalesce(liveRangeEquivalenceClassSet, threads, unknownFragments);
@ -47,15 +47,16 @@ public class Pass4ZeroPageCoalesce extends Pass2Base {
*
* @return The threads.
*/
public static Collection<ScopeRef> getThreadHeads(ProgramScope programScope) {
public static Collection<ScopeRef> getThreadHeads(Program program) {
ArrayList<ScopeRef> threadHeads = new ArrayList<>();
Collection<Procedure> procedures = programScope.getAllProcedures(true);
Collection<Procedure> procedures = program.getScope().getAllProcedures(true);
for(Procedure procedure : procedures) {
if(procedure.getInterruptType() != null) {
threadHeads.add(procedure.getRef());
}
if(procedure.getFullName().equals(SymbolRef.MAIN_PROC_NAME)) {
threadHeads.add(procedure.getRef());
continue;
}
if(Pass2ConstantIdentification.isAddressOfUsed(procedure.getRef(), program)) {
threadHeads.add(procedure.getRef());
}
}
return threadHeads;
@ -109,7 +110,7 @@ public class Pass4ZeroPageCoalesce extends Pass2Base {
* @return True if the two equivalence classes can be coalesced into one without problems.
*/
private static boolean canCoalesceThreads(LiveRangeEquivalenceClass ec1, LiveRangeEquivalenceClass ec2, Collection<ScopeRef> threadHeads, Program program) {
if(threadHeads.size()>=1) {
if(threadHeads.size()<=1) {
return true;
}
CallGraph callGraph = program.getCallGraph();

View File

@ -20,7 +20,7 @@ public class Pass4ZeroPageCoalesceAssignment extends Pass2Base {
public void coalesce() {
CoalesceVarScores coalesceVarScores = new CoalesceVarScores(getProgram());
LinkedHashSet<String> unknownFragments = new LinkedHashSet<>();
Collection<ScopeRef> threadHeads = Pass4ZeroPageCoalesce.getThreadHeads(getSymbols());
Collection<ScopeRef> threadHeads = Pass4ZeroPageCoalesce.getThreadHeads(getProgram());
boolean change;
do {

View File

@ -0,0 +1,59 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.asm.*;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.values.ScopeRef;
import dk.camelot64.kickc.model.values.SymbolRef;
import java.util.ListIterator;
/**
* If the main method is called by JSR this adds an additional RTS
*/
public class Pass5AddMainRts extends Pass5AsmOptimization {
public Pass5AddMainRts(Program program) {
super(program);
}
public boolean optimize() {
for(AsmSegment segment : getAsmProgram().getSegments()) {
String scopeLabel = segment.getScopeLabel();
if(scopeLabel.equals(ScopeRef.ROOT.getFullName())) {
ListIterator<AsmLine> lineIterator = segment.getLines().listIterator();
while(lineIterator.hasNext()) {
AsmLine line = lineIterator.next();
if(line instanceof AsmInstruction) {
AsmInstruction instruction = (AsmInstruction) line;
if(instruction.getType().getMnemnonic().equals("jsr")) {
if(instruction.getParameter().equals(SymbolRef.MAIN_PROC_NAME)) {
// Add RTS if it is missing
if(!lineIterator.hasNext()) {
addRts(lineIterator);
return true;
}
AsmLine nextLine = lineIterator.next();
if(!(nextLine instanceof AsmInstruction)) {
addRts(lineIterator);
return true;
}
AsmInstruction nextInstruction = (AsmInstruction) nextLine;
if(!nextInstruction.getType().getMnemnonic().equals("rts")) {
addRts(lineIterator);
return true;
}
}
}
}
}
}
}
return false;
}
private void addRts(ListIterator<AsmLine> lineIterator) {
lineIterator.add(new AsmInstruction(AsmInstructionSet.getInstructionType("rts", AsmAddressingMode.NON, false), null));
getLog().append("Adding RTS to root block ");
}
}

View File

@ -3,10 +3,7 @@ package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.VariableReferenceInfos;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.statements.StatementCall;
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.ConstantVar;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.values.LValue;
@ -64,6 +61,20 @@ public class PassNEliminateUnusedVars extends Pass2SsaOptimization {
call.setlValue(null);
modified = true;
}
} else if(statement instanceof StatementCallPointer) {
StatementCallPointer call = (StatementCallPointer) statement;
LValue lValue = call.getlValue();
if(lValue instanceof VariableRef && referenceInfos.isUnused((VariableRef) lValue) && !Pass2ConstantIdentification.isAddressOfUsed((VariableRef) lValue, getProgram())) {
if(getLog().isVerbosePass1CreateSsa() || getLog().isVerboseSSAOptimize()) {
getLog().append("Eliminating unused variable - keeping the call " + lValue.toString(getProgram()));
}
Variable variable = getScope().getVariable((VariableRef) lValue);
if(variable != null) {
variable.getScope().remove(variable);
}
call.setlValue(null);
modified = true;
}
} else if(statement instanceof StatementPhiBlock) {
StatementPhiBlock statementPhi = (StatementPhiBlock) statement;
ListIterator<StatementPhiBlock.PhiVariable> phiVarIt = statementPhi.getPhiVariables().listIterator();

View File

@ -5,10 +5,7 @@ import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.VariableReferenceInfos;
import dk.camelot64.kickc.model.iterator.ProgramValue;
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.statements.StatementCall;
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
import dk.camelot64.kickc.model.statements.*;
import dk.camelot64.kickc.model.symbols.SymbolVariable;
import dk.camelot64.kickc.model.values.*;
@ -210,6 +207,12 @@ public class PassNVariableReferenceInfos extends Pass2SsaOptimization {
defined.add((VariableRef) ((StatementCall) stmt).getlValue());
}
return defined;
} else if(stmt instanceof StatementCallPointer) {
List<VariableRef> defined = new ArrayList<>();
if(((StatementCallPointer) stmt).getlValue() instanceof VariableRef) {
defined.add((VariableRef) ((StatementCallPointer) stmt).getlValue());
}
return defined;
}
return new ArrayList<>();
}

View File

@ -32,6 +32,141 @@ public class TestPrograms {
public TestPrograms() {
}
@Test
public void testIllegalVoidParameter() throws IOException, URISyntaxException {
assertError("illegal-void-parameter", "Illegal void parameter");
}
@Test
public void testIllegalUnnamedParameter() throws IOException, URISyntaxException {
assertError("illegal-unnamed-parameter", "Illegal unnamed parameter");
}
@Test
public void testFire() throws IOException, URISyntaxException {
compileAndCompare("examples/fire/fire");
}
@Test
public void testCTypes() throws IOException, URISyntaxException {
compileAndCompare("c-types");
}
@Test
public void testPlus0() throws IOException, URISyntaxException {
compileAndCompare("plus-0");
}
@Test
public void testPlasma2() throws IOException, URISyntaxException {
compileAndCompare("examples/plasma/plasma-unroll");
}
@Test
public void testPlasma() throws IOException, URISyntaxException {
compileAndCompare("examples/plasma/plasma");
}
@Test
public void testTernary3() throws IOException, URISyntaxException {
compileAndCompare("ternary-3");
}
@Test
public void testTernary2() throws IOException, URISyntaxException {
compileAndCompare("ternary-2");
}
@Test
public void testTernary1() throws IOException, URISyntaxException {
compileAndCompare("ternary-1");
}
@Test
public void testPointerPointer3() throws IOException, URISyntaxException {
compileAndCompare("pointer-pointer-3");
}
@Test
public void testPointerPointer2() throws IOException, URISyntaxException {
compileAndCompare("pointer-pointer-2");
}
@Test
public void testPointerPointer1() throws IOException, URISyntaxException {
compileAndCompare("pointer-pointer-1" );
}
@Test
public void testFunctionPointerNoargCall10() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-call-10");
}
@Test
public void testFunctionPointerNoargCall9() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-call-9");
}
@Test
public void testFunctionPointerNoargCall8() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-call-8");
}
@Test
public void testFunctionPointerNoargCall7() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-call-7");
}
@Test
public void testFunctionPointerNoargCall6() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-call-6");
}
@Test
public void testFunctionPointerNoargCall5() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-call-5");
}
@Test
public void testFunctionPointerNoargCall4() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-call-4");
}
@Test
public void testFunctionPointerNoargCall3() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-call-3");
}
@Test
public void testFunctionPointerNoargCall2() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-call-2");
}
@Test
public void testFunctionPointerNoargCall() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-call");
}
@Test
public void testFunctionPointerReturn() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-return");
}
@Test
public void testFunctionPointerNoarg3() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-3");
}
@Test
public void testFunctionPointerNoarg2() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-2");
}
@Test
public void testFunctionPointerNoarg() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg");
}
@Test
public void testLoopBreakContinue() throws IOException, URISyntaxException {
compileAndCompare("loop-break-continue");
@ -59,7 +194,7 @@ public class TestPrograms {
@Test
public void testLocalScopeLoops() throws IOException, URISyntaxException {
compileAndCompare("localscope-loops", getLogSysout());
compileAndCompare("localscope-loops");
}
@Test
@ -1420,11 +1555,11 @@ public class TestPrograms {
@AfterClass
public static void tearDown() {
CompileLog log = getLogSysout();
CompileLog log = log();
AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false);
}
private static CompileLog getLogSysout() {
private static CompileLog log() {
CompileLog log = new CompileLog();
log.setSysOut(true);
return log;

71
src/test/kc/c-types.kc Normal file
View File

@ -0,0 +1,71 @@
// Tests the different standard C types
import "print"
void main() {
print_cls();
testChar();
testShort();
testInt();
testLong();
}
void testChar() {
unsigned char u = 14;
char n = -14;
signed char s = -14;
print_str("char: @");
print_byte(u);
print_char(' ');
print_sbyte(n);
print_char(' ');
print_sbyte(s);
print_ln();
}
void testShort() {
unsigned short u = 1400;
short n = -1400;
signed short s = -1400;
print_str("short: @");
print_word(u);
print_char(' ');
print_sword(n);
print_char(' ');
print_sword(s);
print_ln();
}
void testInt() {
unsigned int u = 1400;
int n = -1400;
signed int s = -1400;
print_str("int: @");
print_word(u);
print_char(' ');
print_sword(n);
print_char(' ');
print_sword(s);
print_ln();
}
void testLong() {
unsigned long u = 140000;
long n = -140000;
signed long s = -140000;
print_str("long: @");
print_dword(u);
print_char(' ');
print_sdword(n);
print_char(' ');
print_sdword(s);
print_ln();
}

View File

@ -21,7 +21,7 @@ void sid_rnd_init() {
// Get a random number from the SID voice 3,
// Must be initialized with sid_rnd_init()
byte sid_rnd() {
inline byte sid_rnd() {
return *SID_VOICE3_OSC;
}

View File

@ -0,0 +1,85 @@
// A KickC version of the fire routine from the CC65 samples
// (w)2002 by groepaz/hitmen
// Cleanup and porting to CC65 by Ullrich von Bassewitz and Greg King .
// Ported to KickC by Jesper Gravgaard.
// Original source https://github.com/cc65/cc65/blob/master/samples/fire.c
import "c64"
import "sid"
unsigned char* SCREEN1 = 0x3800;
unsigned char* SCREEN2 = 0x3c00;
unsigned char* BUFFER = 0x4000;
unsigned char* CHARSET = 0x3000;
void main() {
asm { sei }
*BORDERCOL = BLACK;
*BGCOL = BLACK;
fillscreen(BUFFER, 00);
fillscreen(SCREEN1, 00);
fillscreen(SCREEN2, 00);
fillscreen(COLS, YELLOW);
sid_rnd_init();
makecharset(CHARSET);
// Show double-buffered fire
while(true) {
fire(SCREEN1);
*D018 = toD018(SCREEN1, CHARSET);
fire(SCREEN2);
*D018 = toD018(SCREEN2, CHARSET);
}
}
// Animate the fire on the passe screen. Uses BUFFER to store the current values.
void fire(unsigned char* screenbase) {
// Average characters from below the current character (24 lines)
unsigned char* screen = screenbase;
unsigned char* buffer = BUFFER;
while (buffer != (BUFFER + (24 * 40))) {
unsigned char c = ( buffer[40-1] + buffer[40-1] + buffer[40] + buffer[41] ) >> 2;
if (c > 2) {
c -= 3;
}
*screen = *buffer = c;
++screen;
++buffer;
}
// Add one new random line at the bottom
screen = (screenbase + (24 * 40));
buffer = (BUFFER + (24 * 40));
while(buffer != (BUFFER+(25*40))) {
*screen++ = *buffer++ = 0x30 + (sid_rnd()) >> 4;
}
}
// Make a fire-friendly charset in chars $00-$3f of the passed charset
void makecharset(byte* charset) {
const unsigned char[8] bittab = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
for (unsigned char *font = charset; font != (charset+(1*8)); ++font)
*font = 0x00;
for (unsigned char *font = (charset+(64*8)); font != (charset+(256*8)); ++font)
*font = 0xff;
for (unsigned char c = 0; c < 0x40; ++c) {
unsigned char bc = 0;
for (unsigned char i = 0; i < 8; i++){
unsigned char b = 0;
for (unsigned char ii = 0; ii < 8; ii++) {
bc += c;
if (bc > 0x3f) {
bc = bc - 0x40;
b += bittab[(ii + (i & 1)) & 0x7];
}
}
(charset + (1 * 8)) [(((unsigned short)c) << 3) + i] = b;
}
}
}
// Fill a screen (1000 bytes) with a specific byte
void fillscreen(unsigned char* screen, unsigned char fill) {
for( unsigned word i : 0..999) {
*screen++ = fill;
}
}

View File

@ -0,0 +1,27 @@
// SID registers for random number generation
const word* SID_VOICE3_FREQ = $d40e;
const byte* SID_VOICE3_FREQ_LOW = $d40e;
const byte* SID_VOICE3_FREQ_HIGH = $d40f;
const byte* SID_VOICE3_CONTROL = $d412;
const byte SID_CONTROL_NOISE = $80;
const byte SID_CONTROL_PULSE = $40;
const byte SID_CONTROL_SAWTOOTH = $20;
const byte SID_CONTROL_TRIANGLE = $10;
const byte SID_CONTROL_TEST = $08;
const byte SID_CONTROL_RING = $04;
const byte SID_CONTROL_SYNC = $02;
const byte SID_CONTROL_GATE = $01;
const byte* SID_VOICE3_OSC = $d41b;
// Initialize SID voice 3 for random number generation
void sid_rnd_init() {
*SID_VOICE3_FREQ = $ffff;
*SID_VOICE3_CONTROL = SID_CONTROL_NOISE;
}
// Get a random number from the SID voice 3,
// Must be initialized with sid_rnd_init()
byte sid_rnd() {
return *SID_VOICE3_OSC;
}

View File

@ -0,0 +1,91 @@
// A KickC version of the plasma routine from the CC65 samples
// This version has an unrolled inner loop to reach ~50FPS
// (w)2001 by groepaz/hitmen
// Cleanup and porting to CC65 by Ullrich von Bassewitz.
// Ported to KickC by Jesper Gravgaard.
// Original source https://github.com/cc65/cc65/blob/master/samples/plasma.c
import "c64"
import "print"
import "sid"
const unsigned char* SCREEN1 = $2800;
const unsigned char* CHARSET = $2000;
const unsigned char* SINTABLE = $1f00;
kickasm(pc SINTABLE) {{
.for(var i=0;i<$100;i++)
.byte round(127.5+127.5*sin(toRadians(360*i/256)))
}}
void main() {
asm { sei }
*BORDERCOL = BLUE;
*BGCOL = BLUE;
for(unsigned char* col : COLS..COLS+1000) *col = BLACK;
makecharset(CHARSET);
*D018 = toD018(SCREEN1, CHARSET);
while(true) {
// Show single-buffered plasma
doplasma(SCREEN1);
}
}
// Plasma state variables
unsigned char c1A = 0;
unsigned char c1B = 0;
unsigned char c2A = 0;
unsigned char c2B = 0;
// Render plasma to the passed screen
void doplasma(unsigned char* screen) {
unsigned char[40] xbuf;
unsigned char[25] ybuf;
unsigned char c1a = c1A;
unsigned char c1b = c1B;
for (unsigned char i = 0; i < 25; ++i) {
ybuf[i] = (SINTABLE[c1a] + SINTABLE[c1b]);
c1a += 4;
c1b += 9;
}
c1A += 3;
c1B -= 5;
unsigned char c2a = c2A;
unsigned char c2b = c2B;
for (unsigned char i = 0; i < 40; ++i) {
xbuf[i] = (SINTABLE[c2a] + SINTABLE[c2b]);
c2a += 3;
c2b += 7;
}
c2A += 2;
c2B -= 3;
for (unsigned char i = 0; i < 40; ++i) {
inline for (unsigned char ii = 0; ii < 25; ++ii) {
(screen+ii*40)[i] = (xbuf[i] + ybuf[ii]);
}
}
}
// Make a plasma-friendly charset where the chars are randomly filled
void makecharset(unsigned char* charset) {
const unsigned char[8] bittab = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
sid_rnd_init();
print_cls();
for (unsigned int c = 0; c < 0x100; ++c) {
unsigned char s = SINTABLE[<c];
for ( unsigned char i = 0; i < 8; ++i){
unsigned char b = 0;
for (unsigned char ii = 0; ii < 8; ++ii) {
if ((sid_rnd() & 0xFF) > s) {
b |= bittab[ii];
}
}
charset[(c<<3) + i] = b;
}
if ((c & 0x07) == 0) {
print_char('.');
}
}
}

View File

@ -0,0 +1,94 @@
// A KickC version of the plasma routine from the CC65 samples
// (w)2001 by groepaz/hitmen
// Cleanup and porting to CC65 by Ullrich von Bassewitz.
// Ported to KickC by Jesper Gravgaard.
// Original source https://github.com/cc65/cc65/blob/master/samples/plasma.c
import "c64"
import "print"
import "sid"
const unsigned char* SCREEN1 = $2800;
const unsigned char* SCREEN2 = $2c00;
const unsigned char* CHARSET = $2000;
const unsigned char* SINTABLE = $1f00;
kickasm(pc SINTABLE) {{
.for(var i=0;i<$100;i++)
.byte round(127.5+127.5*sin(toRadians(360*i/256)))
}}
void main() {
asm { sei }
*BORDERCOL = BLUE;
*BGCOL = BLUE;
for(unsigned char* col : COLS..COLS+1000) *col = BLACK;
makecharset(CHARSET);
// Show double-buffered plasma
while(true) {
doplasma(SCREEN1);
*D018 = toD018(SCREEN1, CHARSET);
doplasma(SCREEN2);
*D018 = toD018(SCREEN2, CHARSET);
}
}
// Plasma state variables
unsigned char c1A = 0;
unsigned char c1B = 0;
unsigned char c2A = 0;
unsigned char c2B = 0;
// Render plasma to the passed screen
void doplasma (unsigned char* screen) {
unsigned char[40] xbuf;
unsigned char[25] ybuf;
unsigned char c1a = c1A;
unsigned char c1b = c1B;
for (unsigned char i = 0; i < 25; ++i) {
ybuf[i] = (SINTABLE[c1a] + SINTABLE[c1b]);
c1a += 4;
c1b += 9;
}
c1A += 3;
c1B -= 5;
unsigned char c2a = c2A;
unsigned char c2b = c2B;
for (unsigned char i = 0; i < 40; ++i) {
xbuf[i] = (SINTABLE[c2a] + SINTABLE[c2b]);
c2a += 3;
c2b += 7;
}
c2A += 2;
c2B -= 3;
for (unsigned char ii = 0; ii < 25; ++ii) {
for (unsigned char i = 0; i < 40; ++i) {
screen[i] = (xbuf[i] + ybuf[ii]);
}
screen += 40;
}
}
// Make a plasma-friendly charset where the chars are randomly filled
void makecharset(unsigned char* charset) {
const unsigned char[8] bittab = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
sid_rnd_init();
print_cls();
for (unsigned int c = 0; c < 0x100; ++c) {
unsigned char s = SINTABLE[<c];
for ( unsigned char i = 0; i < 8; ++i){
unsigned char b = 0;
for (unsigned char ii = 0; ii < 8; ++ii) {
if ((sid_rnd() & 0xFF) > s) {
b |= bittab[ii];
}
}
charset[(c<<3) + i] = b;
}
if ((c & 0x07) == 0) {
print_char('.');
}
}
}

View File

@ -0,0 +1,27 @@
// SID registers for random number generation
const word* SID_VOICE3_FREQ = $d40e;
const byte* SID_VOICE3_FREQ_LOW = $d40e;
const byte* SID_VOICE3_FREQ_HIGH = $d40f;
const byte* SID_VOICE3_CONTROL = $d412;
const byte SID_CONTROL_NOISE = $80;
const byte SID_CONTROL_PULSE = $40;
const byte SID_CONTROL_SAWTOOTH = $20;
const byte SID_CONTROL_TRIANGLE = $10;
const byte SID_CONTROL_TEST = $08;
const byte SID_CONTROL_RING = $04;
const byte SID_CONTROL_SYNC = $02;
const byte SID_CONTROL_GATE = $01;
const byte* SID_VOICE3_OSC = $d41b;
// Initialize SID voice 3 for random number generation
void sid_rnd_init() {
*SID_VOICE3_FREQ = $ffff;
*SID_VOICE3_CONTROL = SID_CONTROL_NOISE;
}
// Get a random number from the SID voice 3,
// Must be initialized with sid_rnd_init()
byte sid_rnd() {
return *SID_VOICE3_OSC;
}

View File

@ -0,0 +1,25 @@
// Tests creating and assigning pointers to non-args no-return functions
void main() {
const byte* SCREEN = $400;
void()* f;
for ( byte i: 0..100) {
if((i&1)==0) {
f = &fn1;
} else {
f = &fn2;
}
}
}
void fn1() {
const byte* BORDERCOL = $d020;
(*BORDERCOL)++;
}
void fn2() {
const byte* BGCOL = $d021;
(*BGCOL)++;
}

View File

@ -0,0 +1,35 @@
// Tests creating and assigning pointers to non-args no-return functions - plus inline kickasm-based calling
void main() {
const byte* SCREEN = $400;
void()* f;
byte i = 0;
while(true) {
++i;
if((i&1)==0) {
f = &fn1;
} else {
f = &fn2;
}
kickasm(uses f) {{
jsr ff
}}
}
}
kickasm {{
ff:
jmp (main.f)
}}
void fn1() {
const byte* BORDERCOL = $d020;
(*BORDERCOL)++;
}
void fn2() {
const byte* BGCOL = $d021;
(*BGCOL)++;
}

View File

@ -0,0 +1,30 @@
// Tests calling into different function pointers which call a common sub-method
void main() {
do10(&hello);
do10(&world);
}
void do10(void()* fn) {
for( byte i: 0..9)
(*fn)();
}
void hello() {
print("hello @");
}
void world() {
print("world @");
}
const byte* SCREEN = $0400;
volatile byte idx = 0;
void print(byte* msg) {
byte i=0;
do {
SCREEN[idx++] = msg[i++];
} while(msg[i]!='@');
}

View File

@ -0,0 +1,28 @@
// Tests creating, assigning and calling pointers to non-args no-return functions
void main() {
const byte* SCREEN = $400;
void()* f;
byte i = 0;
while(true) {
++i;
if((i&1)==0) {
f = &fn1;
} else {
f = &fn2;
}
(*f)();
}
}
void fn1() {
const byte* BORDERCOL = $d020;
(*BORDERCOL)++;
}
void fn2() {
const byte* BGCOL = $d021;
(*BGCOL)++;
}

View File

@ -0,0 +1,26 @@
// Tests creating, assigning returning and calling pointers to non-args no-return functions
void main() {
byte i = 0;
while(true) {
*(getfn(++i))();
}
}
void()* getfn(byte b) {
if((b&1)==0) {
return &fn1;
} else {
return &fn2;
}
}
void fn1() {
const byte* BORDERCOL = $d020;
(*BORDERCOL)++;
}
void fn2() {
const byte* BGCOL = $d021;
(*BGCOL)++;
}

View File

@ -0,0 +1,18 @@
// Tests creating, assigning returning and calling pointers to non-args no-return functions
void main() {
byte i = 0;
while(true) {
*(getfn(++i))();
}
}
void()* getfn(byte b) {
return &fn1;
}
void fn1() {
const byte* BORDERCOL = $d020;
(*BORDERCOL)++;
}

View File

@ -0,0 +1,23 @@
// Tests calling into arrays of pointers to non-args no-return functions
void()*[2] fns = { &fn1, &fn2};
void main() {
byte i = 0;
while(true) {
void()* f = fns[(++i&1)<<1];
(*f)();
}
}
void fn1() {
const byte* BORDERCOL = $d020;
(*BORDERCOL)++;
}
void fn2() {
const byte* BGCOL = $d021;
(*BGCOL)++;
}

View File

@ -0,0 +1,16 @@
// Tests calling into a function pointer with local variables
void main() {
void()* cls = &fn1;
for(byte* cols = $d800; cols<$d800+1000;cols++) {
(*cls)();
(*cols)++;
}
}
void fn1() {
for(byte* screen=$400;screen<$400+1000;screen++)
(*screen)++;
}

View File

@ -0,0 +1,26 @@
// Tests calling into a function pointer with local variables
void main() {
void()* f = &hello;
do10(f);
}
void do10(void()* fn) {
for( byte i: 0..9)
(*fn)();
}
const byte* SCREEN = $0400;
const byte[] msg = "hello @";
volatile byte idx = 0;
void hello() {
byte i=0;
do {
SCREEN[idx++] = msg[i++];
} while(msg[i]!='@');
}

View File

@ -0,0 +1,31 @@
// Tests calling into a function pointer with local variables
void main() {
void()* f = &hello;
msg = msg1;
do10(f);
msg = msg2;
do10(f);
}
void do10(void()* fn) {
for( byte i: 0..9)
(*fn)();
}
const byte* SCREEN = $0400;
const byte[] msg1 = "hello @";
const byte[] msg2 = "world @";
volatile byte* msg;
volatile byte idx = 0;
void hello() {
byte i=0;
do {
SCREEN[idx++] = msg[i++];
} while(msg[i]!='@');
}

View File

@ -0,0 +1,19 @@
// Tests calling into a function pointer which modifies global volatile
const byte* SCREEN = $0400;
volatile byte idx = 0;
void main() {
void()* f = &fn1;
(*f)();
SCREEN[idx] = 'a';
(*f)();
SCREEN[idx] = 'a';
}
void fn1() {
idx++;
}

View File

@ -0,0 +1,11 @@
// Tests creating, assigning and calling pointers to non-args no-return functions
void main() {
void()* f = &fn1;
(*f)();
}
void fn1() {
const byte* BORDERCOL = $d020;
(*BORDERCOL)++;
}

View File

@ -0,0 +1,24 @@
// Tests creating pointers to non-args no-return functions
void main() {
const byte* SCREEN = $400;
void()* f;
f = &fn1;
SCREEN[0] = <(word)f;
SCREEN[1] = >(word)f;
f = &fn2;
SCREEN[2] = <(word)f;
SCREEN[3] = >(word)f;
}
void fn1() {
const byte* BORDERCOL = $d020;
(*BORDERCOL)++;
}
void fn2() {
const byte* BGCOL = $d021;
(*BGCOL)++;
}

View File

@ -0,0 +1,30 @@
// Tests creating and assigning pointers to non-args return with function value
void main() {
const byte* SCREEN = $400;
byte()* f;
byte i = 0;
while(true) {
++i;
if((i&1)==0) {
f = &fn1;
} else {
f = &fn2;
}
SCREEN[0] = (byte)f;
}
}
byte fn1() {
const byte* BORDERCOL = $d020;
(*BORDERCOL)++;
return *BORDERCOL;
}
byte fn2() {
const byte* BGCOL = $d021;
(*BGCOL)++;
return *BGCOL;
}

View File

@ -0,0 +1,4 @@
// Tests that the compiler complains if a non-void parameter has no name
void main(char) {
}

View File

@ -0,0 +1,4 @@
// Tests that the compiler complains if a non-void parameter has no name
void main(char c, void) {
}

View File

@ -1,12 +1,12 @@
byte* SCREEN = $0400;
byte char = 'a';
byte ch = 'a';
byte num = 1;
byte[] str = "bc"+"d"+'e';
byte[] nums = { 2, 3, 4, 5};
void main() {
SCREEN[0] = char;
SCREEN[0] = ch;
SCREEN[2] = num;
for(byte i : 0..3) {
SCREEN[4+i] = str[i];

View File

@ -74,12 +74,12 @@ interrupt(kernel_min) void plex_irq() {
// The raster loop
void loop() {
// The current index into the y-sinus
volatile byte sin_idx = 0; // without volatile gives wrong asm
byte sin_idx = 0;
while(true) {
while(!framedone) { }
*BORDERCOL = RED;
// Assign sinus positions
volatile byte y_idx = sin_idx; // without volatile gives wrong asm
byte y_idx = sin_idx;
for(byte sy: 0..PLEX_COUNT-1) {
PLEX_YPOS[sy] = YSIN[y_idx];
y_idx += 8;

14
src/test/kc/plus-0.kc Normal file
View File

@ -0,0 +1,14 @@
// Tests elimination of plus 0
void main() {
fill((byte*)$400,'a');
fill((byte*)$2000,'b');
}
void fill(byte* screen, byte ch) {
for(byte i: 0..39) {
inline for( byte j: 0..2 ) {
(screen+j*40)[i] = ch;
}
}
}

View File

@ -0,0 +1,11 @@
// Tests a simple pointer to a pointer
void main() {
const byte* SCREEN = $400;
byte b = 'a';
byte* pb = &b;
byte** ppb = &pb;
*SCREEN = **ppb;
}

View File

@ -0,0 +1,30 @@
// Tests pointer to pointer in a more complex setup
void main() {
byte* screen = $400;
byte* text;
for(byte i: 0..20) {
nexttext(&text);
while(*text!='@') {
*screen++ = *text++;
}
}
}
byte[] text1 = "camelot @";
byte[] text2 = "rex @";
byte textid = 0;
// Choose the next text to show - by updating the text pointer pointed to by the passed pointer to a pointer
void nexttext(byte** textp) {
if((textid++&1)==0) {
*textp = text1;
} else {
*textp = text2;
}
}

View File

@ -0,0 +1,18 @@
// Tests pointer to pointer in a more complex setup
byte* screen = $400;
byte* screen1 = $400;
byte* screen2 = $400+40;
void main() {
setscreen(&screen, screen1);
screen[0] = 'a';
setscreen(&screen, screen2);
screen[0] = 'a';
}
void setscreen(byte** screen, byte* val) {
*screen = val;
}

View File

@ -1,19 +1,19 @@
byte* SCREEN= $400;
byte line = $40;
byte char = line;
byte ch = line;
void main() {
ln();
char++;
ch++;
ln();
char++;
ch++;
ln();
*SCREEN = char;
*SCREEN = ch;
}
void ln() {
line = line + $2;
char = line;
ch = line;
}

8
src/test/kc/ternary-1.kc Normal file
View File

@ -0,0 +1,8 @@
// Tests the ternary operator
void main() {
const byte* SCREEN = $400;
for( byte i: 0..9) {
SCREEN[i] = i<5?'a':'b';
}
}

Some files were not shown because too many files have changed in this diff Show More