/** * Copyright 2012 Tobias Gierke <tobias.gierke@code-sourcery.de> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.codesourcery.jasm16.ast; import org.apache.commons.lang.ObjectUtils; import de.codesourcery.jasm16.Register; import de.codesourcery.jasm16.compiler.ICompilationContext; import de.codesourcery.jasm16.compiler.ISymbolTable; import de.codesourcery.jasm16.exceptions.ParseException; import de.codesourcery.jasm16.lexer.IToken; import de.codesourcery.jasm16.lexer.TokenType; import de.codesourcery.jasm16.parser.IParseContext; import de.codesourcery.jasm16.parser.Operator; /** * AST node that represents a register reference (identifier). * * @author tobias.gierke@code-sourcery.de */ public class RegisterReferenceNode extends TermNode { private Register register; private boolean hasPreDecrement; private boolean hasPostIncrement; @Override public boolean equals(Object obj) { if ( obj == this ) { return true; } if ( obj instanceof RegisterReferenceNode) { final RegisterReferenceNode other = (RegisterReferenceNode) obj; return ObjectUtils.equals( this.register , other.register ) && this.hasPostIncrement == other.hasPostIncrement && this.hasPreDecrement == other.hasPreDecrement; } return false; } @Override protected RegisterReferenceNode parseInternal(IParseContext context) throws ParseException { /* 0x18: POP / [SP++] * 0x19: PEEK / [SP] * 0x1a: PUSH / [--SP] */ IToken token = context.peek(); if ( token.hasType( TokenType.PICK ) || token.hasType( TokenType.PUSH ) || token.hasType( TokenType.PEEK ) || token.hasType( TokenType.POP ) ) { register = Register.SP; token = context.read(); switch( token.getType() ) { case PICK: break; case PUSH: hasPreDecrement = true; break; case PEEK: break; case POP: hasPostIncrement = true; break; default: throw new RuntimeException("Unreachable code reached"); } mergeWithAllTokensTextRegion( token ); return this; } final int startOffset = context.currentParseIndex(); if ( token.hasType( TokenType.OPERATOR ) ) { final Operator op = Operator.fromString( token.getContents() ); if ( op != Operator.DECREMENT ) { throw new ParseException("Operator "+op+" not supported with register", token ); } mergeWithAllTokensTextRegion( context.read() ); hasPreDecrement = true; } token = context.read( "expected a register identifier",TokenType.CHARACTERS ); if ( ! Register.isRegisterIdentifier( token.getContents() ) ) { throw new ParseException("Not a valid register: '"+token.getContents()+"'",token ); } register = Register.fromString( token.getContents() ); mergeWithAllTokensTextRegion( token ); if ( ! context.eof() && context.peek().hasType( TokenType.OPERATOR ) ) { final Operator op = Operator.fromString( context.peek().getContents() ); if ( op == Operator.INCREMENT ) { mergeWithAllTokensTextRegion( context.read() ); hasPostIncrement = true; } } if ( hasPreDecrement || hasPostIncrement ) { if ( hasPreDecrement && hasPostIncrement ) { throw new ParseException("Register cannot have both pre-decrement and post-increment",startOffset, context.currentParseIndex()-startOffset); } if ( hasPreDecrement && ! register.supportsIndirectWithPreDecrement() ) { throw new ParseException("Register "+register+" does not support pre-decrement",startOffset, context.currentParseIndex()-startOffset); } if ( hasPostIncrement && ! register.supportsIndirectWithPostIncrement() ) { throw new ParseException("Register "+register+" does not support post-increment",startOffset, context.currentParseIndex()-startOffset); } } return this; } @Override public TermNode reduce(ICompilationContext context) { return (TermNode) createCopy(false); } @Override protected RegisterReferenceNode copySingleNode() { final RegisterReferenceNode result = new RegisterReferenceNode(); result.register = register; result.hasPostIncrement = hasPostIncrement; result.hasPreDecrement = hasPreDecrement; return result; } public boolean hasPreDecrement() { return hasPreDecrement; } public boolean hasPostIncrement() { return hasPostIncrement; } public Register getRegister() { return register; } @Override public String toString() { String result=""; if ( hasPreDecrement ) { result = "--"; } result = register != null ? register.toString() : "<null register?>"; if ( hasPostIncrement ) { result = result + "++"; } return result; } @Override public boolean supportsChildNodes() { return false; } @Override public Long calculate(ISymbolTable symbolTable) { return Long.valueOf( 0 ); } }