<commit_before>package asmcup.compiler;

import java.util.*;

import asmcup.vm.VMConsts;

public class Compiler implements VMConsts {
	protected ArrayList<Statement> statements;
	protected HashMap<String, Integer> labels;
	protected byte[] ram;
	protected int pc;

	protected int currentLine = 0;
		
	protected void write8(int value) {
		ram[pc] = (byte)(value & 0xFF);
		pc = (pc + 1) & 0xFF;
	}
	
	protected void writeOp(int op, int data) {
		if ((op >> 2) != 0) {
			throw new IllegalArgumentException("Opcode is greater than 2-bits");
		}
		
		if ((data >> 6) != 0) {
			throw new IllegalArgumentException("Opcode data is greater than 6-bits");
		}
		
		write8(op | (data << 2));
	}
	
	protected void write16(int value) {
		write8(value & 0xFF);
		write8(value >> 8);
	}
	
	protected void write32(int value) {
		write16(value & 0xFFFF);
		write16(value >> 16);
	}
	
	protected void writeFloat(float value) {
		write32(Float.floatToRawIntBits(value));
	}
	
	public byte[] compile(String[] lines) {
		ram = new byte[256];
		labels = new HashMap<>();
		statements = new ArrayList<>();
		pc = 0;
		
		for (String line : lines) {
			currentLine++;
			parseLine(line);
		}
		
		pc = 0;
		
		for (Statement statement : statements) {
			pc += statement.measure();
		}
		
		pc = 0;
		
		for (Statement statement : statements) {
			statement.compile();
		}
		
		labels.clear();
		statements.clear();
		labels = null;
		statements = null;
		pc = 0;
		
		byte[] compiled = ram;
		ram = null;
		return compiled;
	}
	
	public byte[] compile(String source) {
		return compile(source.split("\n"));
	}
	
	protected void parseLine(String line) {
		line = line.trim();
		
		if (line.isEmpty()) {
			return;
		}
		
		line = parseComments(line);
		line = parseLabels(line);
		
		if (line.isEmpty()) {
			return;
		}
		
		String[] parts = line.split("\\s+", 2);
		
		if (parts.length <= 0) {
			return;
		}
		
		String cmd = parts[0].toLowerCase().trim();
		String[] args = parseArgs(parts);
		parseStatement(cmd, args);
	}
	
	protected void parseStatement(String cmd, String[] args) {
		switch (cmd) {
		case "db":
		case "db8":
			db(args);
			break;
		case "dbf":
			dbf(args);
			break;
		case "push8":
			push8(args);
			break;
		case "push8r":
			push8r(args);
			break;
		case "pop8":
			pop8(args);
			break;
		case "pop8r":
			pop8r(args);
			break;
		case "pushf":
			pushf(args);
			break;
		case "popf":
			popf(args);
			break;
		case "jne":
		case "jnz":
			jnz(args);
			break;
		case "jnzr":
		case "jner":
			jnzr(args);
			break;
		case "jmp":
			jmp(args);
			break;
		default:
			func(cmd, args);
			break;
		}
	}
	
	final static byte[] NO_DATA = {};
	
	protected void func(String cmd, String[] args) {
		if (!VMFuncTable.exists(cmd)) {
			throw new IllegalArgumentException("Unknown function " + cmd);
		}
		
		immediate(OP_FUNC, VMFuncTable.parse(cmd), NO_DATA);
	}
	
	protected void db(String[] args) {
		statements.add(new Statement() {
			public int measure() {
				return args.length;
			}
			
			public void compile() {
				for (String s : args) {
					write8(parseLiteral(s));
				}
			}
		});
	}
	
	protected void dbf(String[] args) {
		statements.add(new Statement() {
			public int measure() {
				return args.length * 4;
			}
			
			public void compile() {
				for (String s : args) {
					writeFloat(Float.parseFloat(s));
				}
			}
		});
	}
	
	protected void push8(String[] args) {
		String s = expectOne(args);
		
		if (isLiteral(s)) {
			pushLiteral8(s);
		} else if (s.startsWith("&")) {
			reference(OP_PUSH, MAGIC_PUSH_BYTE_IMMEDIATE, s);
		} else {
			reference(OP_PUSH, MAGIC_PUSH_BYTE_MEMORY, s);
		}
	}
	
	protected void pushLiteral8(String s) {
		switch (parseLiteral(s)) {
		case 0:
			immediate(OP_FUNC, F_C_0, NO_DATA);
			break;
		case 1:
			immediate(OP_FUNC, F_C_1, NO_DATA);
			break;
		case 2:
			immediate(OP_FUNC, F_C_2, NO_DATA);
			break;
		case 3:
			immediate(OP_FUNC, F_C_3, NO_DATA);
			break;
		case 4:
			immediate(OP_FUNC, F_C_4, NO_DATA);
			break;
		case 255:
			immediate(OP_FUNC, F_C_255, NO_DATA);
			break;
		default:
			immediate(OP_PUSH, MAGIC_PUSH_BYTE_IMMEDIATE, s);<commit_msg>Fixed bug with "&" using wrong label key in compiler.<commit_after>package asmcup.compiler;

import java.util.*;

import asmcup.vm.VMConsts;

public class Compiler implements VMConsts {
	protected ArrayList<Statement> statements;
	protected HashMap<String, Integer> labels;
	protected byte[] ram;
	protected int pc;

	protected int currentLine = 0;
		
	protected void write8(int value) {
		ram[pc] = (byte)(value & 0xFF);
		pc = (pc + 1) & 0xFF;
	}
	
	protected void writeOp(int op, int data) {
		if ((op >> 2) != 0) {
			throw new IllegalArgumentException("Opcode is greater than 2-bits");
		}
		
		if ((data >> 6) != 0) {
			throw new IllegalArgumentException("Opcode data is greater than 6-bits");
		}
		
		write8(op | (data << 2));
	}
	
	protected void write16(int value) {
		write8(value & 0xFF);
		write8(value >> 8);
	}
	
	protected void write32(int value) {
		write16(value & 0xFFFF);
		write16(value >> 16);
	}
	
	protected void writeFloat(float value) {
		write32(Float.floatToRawIntBits(value));
	}
	
	public byte[] compile(String[] lines) {
		ram = new byte[256];
		labels = new HashMap<>();
		statements = new ArrayList<>();
		pc = 0;
		
		for (String line : lines) {
			currentLine++;
			parseLine(line);
		}
		
		pc = 0;
		
		for (Statement statement : statements) {
			pc += statement.measure();
		}
		
		pc = 0;
		
		for (Statement statement : statements) {
			statement.compile();
		}
		
		labels.clear();
		statements.clear();
		labels = null;
		statements = null;
		pc = 0;
		
		byte[] compiled = ram;
		ram = null;
		return compiled;
	}
	
	public byte[] compile(String source) {
		return compile(source.split("\n"));
	}
	
	protected void parseLine(String line) {
		line = line.trim();
		
		if (line.isEmpty()) {
			return;
		}
		
		line = parseComments(line);
		line = parseLabels(line);
		
		if (line.isEmpty()) {
			return;
		}
		
		String[] parts = line.split("\\s+", 2);
		
		if (parts.length <= 0) {
			return;
		}
		
		String cmd = parts[0].toLowerCase().trim();
		String[] args = parseArgs(parts);
		parseStatement(cmd, args);
	}
	
	protected void parseStatement(String cmd, String[] args) {
		switch (cmd) {
		case "db":
		case "db8":
			db(args);
			break;
		case "dbf":
			dbf(args);
			break;
		case "push8":
			push8(args);
			break;
		case "push8r":
			push8r(args);
			break;
		case "pop8":
			pop8(args);
			break;
		case "pop8r":
			pop8r(args);
			break;
		case "pushf":
			pushf(args);
			break;
		case "popf":
			popf(args);
			break;
		case "jne":
		case "jnz":
			jnz(args);
			break;
		case "jnzr":
		case "jner":
			jnzr(args);
			break;
		case "jmp":
			jmp(args);
			break;
		default:
			func(cmd, args);
			break;
		}
	}
	
	final static byte[] NO_DATA = {};
	
	protected void func(String cmd, String[] args) {
		if (!VMFuncTable.exists(cmd)) {
			throw new IllegalArgumentException("Unknown function " + cmd);
		}
		
		immediate(OP_FUNC, VMFuncTable.parse(cmd), NO_DATA);
	}
	
	protected void db(String[] args) {
		statements.add(new Statement() {
			public int measure() {
				return args.length;
			}
			
			public void compile() {
				for (String s : args) {
					write8(parseLiteral(s));
				}
			}
		});
	}
	
	protected void dbf(String[] args) {
		statements.add(new Statement() {
			public int measure() {
				return args.length * 4;
			}
			
			public void compile() {
				for (String s : args) {
					writeFloat(Float.parseFloat(s));
				}
			}
		});
	}
	
	protected void push8(String[] args) {
		String s = expectOne(args);
		
		if (isLiteral(s)) {
			pushLiteral8(s);
		} else if (s.startsWith("&")) {
			reference(OP_PUSH, MAGIC_PUSH_BYTE_IMMEDIATE, s.substring(1));
		} else {
			reference(OP_PUSH, MAGIC_PUSH_BYTE_MEMORY, s);
		}
	}
	
	protected void pushLiteral8(String s) {
		switch (parseLiteral(s)) {
		case 0:
			immediate(OP_FUNC, F_C_0, NO_DATA);
			break;
		case 1:
			immediate(OP_FUNC, F_C_1, NO_DATA);
			break;
		case 2:
			immediate(OP_FUNC, F_C_2, NO_DATA);
			break;
		case 3:
			immediate(OP_FUNC, F_C_3, NO_DATA);
			break;
		case 4:
			immediate(OP_FUNC, F_C_4, NO_DATA);
			break;
		case 255:
			immediate(OP_FUNC, F_C_255, NO_DATA);
			break;
		default:
			immediate(OP_PUSH, MAGIC_PUSH_BYTE_IMMEDIATE, s);
{'fraction_non_alphanumeric': 0.1455703810554153, 'fraction_numerical': 0.01694915254237288, 'mean_word_length': 3.0704500978473583, 'pattern_counts': {'":': 28, '<': 17, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '107010', 'n_tokens_mistral': 3718, 'n_tokens_neox': 2995, 'n_words': 743}