| @@ -8,6 +8,7 @@ import java.io.IOException; | |||||
| import java.net.Socket; | import java.net.Socket; | ||||
| import com.bitshift.parsing.symbols.Symbols; | import com.bitshift.parsing.symbols.Symbols; | ||||
| import com.bitshift.parsing.utils.PackableMemory; | |||||
| public abstract class Parser implements Runnable { | public abstract class Parser implements Runnable { | ||||
| @@ -48,7 +49,9 @@ public abstract class Parser implements Runnable { | |||||
| PrintWriter clientWriter = new PrintWriter( | PrintWriter clientWriter = new PrintWriter( | ||||
| this.clientSocket.getOutputStream(), true); | this.clientSocket.getOutputStream(), true); | ||||
| clientWriter.println(toClient); | |||||
| PackableMemory mem = new PackableMemory(toClient.length()); | |||||
| String dataSize = new String(mem.mem); | |||||
| clientWriter.println(dataSize + toClient); | |||||
| } catch (IOException ex) { | } catch (IOException ex) { | ||||
| } | } | ||||
| } | } | ||||
| @@ -56,6 +59,6 @@ public abstract class Parser implements Runnable { | |||||
| protected abstract Symbols genSymbols(); | protected abstract Symbols genSymbols(); | ||||
| public abstract void run(); | public abstract void run(); | ||||
| } | } | ||||
| @@ -0,0 +1,89 @@ | |||||
| package com.bitshift.parsing.utils; | |||||
| //This class contains implementations of methods to | |||||
| // -- pack an integer into 4 consecutive bytes of a byte array | |||||
| // -- unpack an integer from 4 consecutive bytes of a byte array | |||||
| // -- exhaustively test the pack and unpack methods. | |||||
| // | |||||
| // This file should be saved as PackableMemory.java. Once it has been | |||||
| // compiled, the tester can be invoked by typing "java PackableMemory" | |||||
| public class PackableMemory { | |||||
| int size; | |||||
| public byte mem[] = null; | |||||
| public PackableMemory(int size) | |||||
| { | |||||
| this.size = size; | |||||
| this.mem = new byte[size]; | |||||
| } | |||||
| // Pack the 4-byte integer val into the four bytes mem[loc]...mem[loc+3]. | |||||
| // The most significant porion of the integer is stored in mem[loc]. | |||||
| // Bytes are masked out of the integer and stored in the array, working | |||||
| // from right(least significant) to left (most significant). | |||||
| void pack(int val, int loc) | |||||
| { | |||||
| final int MASK = 0xff; | |||||
| for (int i = 3; i >= 0; i--) | |||||
| { | |||||
| mem[loc+i] = (byte)(val & MASK); | |||||
| val = val >> 8; | |||||
| } | |||||
| } | |||||
| // Unpack the four bytes mem[loc]...mem[loc+3] into a 4-byte integer, | |||||
| // and return the resulting integer value. | |||||
| // The most significant porion of the integer is stored in mem[loc]. | |||||
| // Bytes are 'OR'ed into the integer, working from left (most significant) | |||||
| // to right (least significant) | |||||
| int unpack(int loc) | |||||
| { | |||||
| final int MASK = 0xff; | |||||
| int v = (int)mem[loc] & MASK; | |||||
| for (int i = 1; i < 4; i++) | |||||
| { | |||||
| v = v << 8; | |||||
| v = v | ((int)mem[loc+i] & MASK); | |||||
| } | |||||
| return v; | |||||
| } | |||||
| // Test the above pack and unpack methods by iterating the following | |||||
| // over all possible 4-byte integers: pack the integer, | |||||
| // then unpack it, and then verify that the unpacked integer equals the | |||||
| // original integer. It tests all nonnegative numbers in ascending order | |||||
| // and then all negative numbers in ascending order. The transition from | |||||
| // positive to negative numbers happens implicitly due to integer overflow. | |||||
| public void packTest() | |||||
| { | |||||
| int i = 0; | |||||
| long k = 0; | |||||
| do | |||||
| { | |||||
| this.pack(i,4); | |||||
| int j = this.unpack(4); | |||||
| if (j != i) | |||||
| { | |||||
| System.out.printf("pack/unpack test failed: i = %d, j = %d\n",i,j); | |||||
| System.exit(0); | |||||
| } | |||||
| i++; k++; | |||||
| } | |||||
| while (i != 0); | |||||
| System.out.printf("pack/unpack test successful, %d iterations\n",k); | |||||
| } | |||||
| // main routine to test the PackableMemory class by running the | |||||
| // packTest() method. | |||||
| public static void main(String[] args) | |||||
| { | |||||
| PackableMemory pm = new PackableMemory(100); | |||||
| pm.packTest(); | |||||
| System.exit(0); | |||||
| } | |||||
| } | |||||
| @@ -1,7 +1,8 @@ | |||||
| import socket, sys | |||||
| import socket, sys, struct | |||||
| file_name = 'resources/<name>.c' | file_name = 'resources/<name>.c' | ||||
| server_socket_number = 5001 | server_socket_number = 5001 | ||||
| recv_size = 8192 | |||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||
| if len(sys.argv) == 1: | if len(sys.argv) == 1: | ||||
| @@ -19,22 +20,37 @@ if __name__ == '__main__': | |||||
| server_socket_number = 5002 | server_socket_number = 5002 | ||||
| elif sys.argv[1] == 'ruby': | elif sys.argv[1] == 'ruby': | ||||
| file_name = "resources/<name>.rb" | |||||
| file_name = "resources/parser.rb" | |||||
| server_socket_number = 5003 | server_socket_number = 5003 | ||||
| client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |||||
| client_socket.connect(("localhost", server_socket_number)) | |||||
| server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |||||
| server_socket.connect(("localhost", server_socket_number)) | |||||
| with open(file_name, "r") as source_file: | with open(file_name, "r") as source_file: | ||||
| source = source_file.read() | source = source_file.read() | ||||
| client_socket.send("%d\n%s" % (len(source), source)); | |||||
| server_socket.send("%d\n%s" % (len(source), source)); | |||||
| data = '' | |||||
| while True: | |||||
| data = client_socket.recv(10000) | |||||
| total_data = []; size_data = cur_data = '' | |||||
| total_size = 0; size = sys.maxint | |||||
| if data != '': | |||||
| client_socket.close() | |||||
| break; | |||||
| while total_size < size: | |||||
| cur_data = server_socket.recv(recv_size) | |||||
| print data; | |||||
| if not total_data: | |||||
| if len(size_data) > 4: | |||||
| size_data += cur_data | |||||
| size = struct.unpack('>i', size_data[:4])[0] | |||||
| recv_size = size | |||||
| if recv_size > sys.maxint: recv_size = sys.maxint | |||||
| total_data.append(size_data[4:]) | |||||
| else: | |||||
| size_data += cur_data | |||||
| else: | |||||
| total_data.append(cur_data) | |||||
| total_size = sum([len(s) for s in total_data]) | |||||
| server_socket.close() | |||||
| print ''.join(total_data); | |||||
| @@ -0,0 +1,126 @@ | |||||
| require 'socket' | |||||
| require 'ruby_parser' | |||||
| require 'sexp_processor' | |||||
| module Bitshift | |||||
| class Parser | |||||
| def initialize(source) | |||||
| @source = source | |||||
| end | |||||
| def parse | |||||
| parser = RubyParser.new | |||||
| tree = parser.parse(@source) | |||||
| puts tree.inspect | |||||
| offset = tree.line - 1 | |||||
| processor = NodeVisitor.new offset | |||||
| processor.process tree | |||||
| return processor.symbols | |||||
| end | |||||
| end | |||||
| class NodeVisitor < SexpProcessor | |||||
| attr_accessor :symbols | |||||
| attr_accessor :offset | |||||
| def initialize(offset) | |||||
| super() | |||||
| @require_empty = false | |||||
| @offset = offset | |||||
| module_hash = Hash.new {|hash, key| hash[key] = Hash.new} | |||||
| class_hash = module_hash.clone | |||||
| function_hash = Hash.new {|hash, key| hash[key] = { calls: [] } } | |||||
| var_hash = Hash.new {|hash, key| hash[key] = [] } | |||||
| @symbols = { | |||||
| modules: module_hash, | |||||
| classes: class_hash, | |||||
| functions: function_hash, | |||||
| vars: var_hash | |||||
| } | |||||
| end | |||||
| def block_position(exp) | |||||
| pos = Hash.new | |||||
| end_ln = (start_ln = exp.line - offset) | |||||
| cur_exp = exp | |||||
| while cur_exp.is_a? Sexp | |||||
| end_ln = cur_exp.line - offset | |||||
| cur_exp = cur_exp.last | |||||
| break if cur_exp == nil | |||||
| end | |||||
| pos[:coord] = { | |||||
| start_ln: start_ln, | |||||
| end_ln: end_ln } | |||||
| return pos | |||||
| end | |||||
| def statement_position(exp) | |||||
| pos = Hash.new | |||||
| end_ln = start_ln = exp.line - offset | |||||
| pos[:coord] = { | |||||
| start_ln: start_ln, | |||||
| end_ln: end_ln } | |||||
| return pos | |||||
| end | |||||
| def process_module(exp) | |||||
| pos = block_position exp | |||||
| exp.shift | |||||
| name = exp.shift | |||||
| symbols[:modules][name] = pos | |||||
| exp.each_sexp {|s| process(s)} | |||||
| return exp.clear | |||||
| end | |||||
| def process_class(exp) | |||||
| pos = block_position exp | |||||
| exp.shift | |||||
| name = exp.shift | |||||
| symbols[:classes][name] = pos | |||||
| exp.each_sexp {|s| process(s)} | |||||
| return exp.clear | |||||
| end | |||||
| def process_defn(exp) | |||||
| pos = block_position exp | |||||
| exp.shift | |||||
| name = exp.shift | |||||
| symbols[:functions][name][:declaration] = pos | |||||
| exp.each_sexp {|s| process(s)} | |||||
| return exp.clear | |||||
| end | |||||
| def process_call(exp) | |||||
| pos = statement_position exp | |||||
| exp.shift | |||||
| exp.shift | |||||
| name = exp.shift | |||||
| symbols[:functions][name][:calls] << pos | |||||
| exp.each_sexp {|s| process(s)} | |||||
| return exp.clear | |||||
| end | |||||
| def process_iasgn(exp) | |||||
| pos = statement_position exp | |||||
| exp.shift | |||||
| name = exp.shift | |||||
| symbols[:vars][name] << pos | |||||
| exp.each_sexp {|s| process(s)} | |||||
| return exp.clear | |||||
| end | |||||
| def process_lasgn(exp) | |||||
| pos = statement_position exp | |||||
| exp.shift | |||||
| name = exp.shift | |||||
| symbols[:vars][name] << pos | |||||
| exp.each_sexp {|s| process(s)} | |||||
| return exp.clear | |||||
| end | |||||
| end | |||||
| end | |||||