@@ -8,6 +8,7 @@ import java.io.IOException; | |||
import java.net.Socket; | |||
import com.bitshift.parsing.symbols.Symbols; | |||
import com.bitshift.parsing.utils.PackableMemory; | |||
public abstract class Parser implements Runnable { | |||
@@ -48,7 +49,9 @@ public abstract class Parser implements Runnable { | |||
PrintWriter clientWriter = new PrintWriter( | |||
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) { | |||
} | |||
} | |||
@@ -56,6 +59,6 @@ public abstract class Parser implements Runnable { | |||
protected abstract Symbols genSymbols(); | |||
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' | |||
server_socket_number = 5001 | |||
recv_size = 8192 | |||
if __name__ == '__main__': | |||
if len(sys.argv) == 1: | |||
@@ -19,22 +20,37 @@ if __name__ == '__main__': | |||
server_socket_number = 5002 | |||
elif sys.argv[1] == 'ruby': | |||
file_name = "resources/<name>.rb" | |||
file_name = "resources/parser.rb" | |||
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: | |||
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 |