@@ -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 |