1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 14:42:11 +02:00

more work on the parser.

This commit is contained in:
Alain Magloire 2002-08-07 03:17:13 +00:00
parent e779696228
commit 945fd6b033
22 changed files with 329 additions and 79 deletions

View file

@ -23,7 +23,7 @@ public class MIPlugin extends Plugin {
}
/**
* Returns the shared instance.
* Returns the singleton.
*/
public static MIPlugin getDefault() {
return plugin;

View file

@ -1,5 +1,6 @@
package org.eclipse.cdt.debug.mi.core;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Observable;
@ -9,8 +10,11 @@ import org.eclipse.cdt.debug.mi.core.command.CommandFactory;
import org.eclipse.cdt.debug.mi.core.output.MIOutput;
import org.eclipse.cdt.debug.mi.core.output.MIParser;
/**
* Represents a GDB/MI session.
* Note that on GNU/Linux the target stream is not
* preceded by the token '@' until this is fix, on GNU/Linux
* there a good change to confuse the parser.
*/
public class MISession extends Observable {
@ -35,14 +39,18 @@ public class MISession extends Observable {
final int STOPPED = 0;
final int RUNNING = 1;
final int SUSPENDED = 1;
int state = STOPPED;
/**
* The constructor.
* Create the gdb session.
*
* @param i the gdb input channel.
* @param o gdb output channel.
*/
public MISession(InputStream i, OutputStream o) {
inChannel = i;
outChannel= o;
outChannel = o;
factory = new CommandFactory();
parser = new MIParser();
txQueue = new Queue();
@ -60,48 +68,84 @@ public class MISession extends Observable {
consoleStream = console;
}
/**
* get Console Stream.
*/
OutputStream getConsoleStream() {
return consoleStream;
}
/**
* Set Target Stream.
*/
public void setTargetStreamOutput(OutputStream target) {
public void setTargetStream(OutputStream target) {
targetStream = target;
}
/**
* Get Target Stream.
*/
OutputStream getTargetStream() {
return targetStream;
}
/**
* Set Log Stream
*/
public void setLogStreamOutput(OutputStream log) {
public void setLogStream(OutputStream log) {
logStream = log;
}
/**
*
* Get Log Stream
*/
OutputStream getLogStream() {
return logStream;
}
/**
* For example the CDI/MI adapters uses the command
* factory to create MI commands this allow overloading.
*/
public CommandFactory getCommandFactory() {
return factory;
}
/**
*
* Set a new factory to use in CDI/MI adapters.
*/
public void setCommandFactory(CommandFactory f) {
factory = f;
}
/**
*
* Return the MI main parser.
*/
public MIParser getMIParser() {
return parser;
}
/**
*
* Reset the parser.
*/
public void setMIParser(MIParser p) {
parser = p;
}
/**
* Reset the default Command Timeout.
*/
public void setCommandTimeout(long timeout) {
cmdTimeout = timeout;
}
/**
* Return the default Command Timeout, default 20 secs.
*/
public long getCommandTimeout() {
return cmdTimeout;
}
/**
* postCommand(cmd, 20 secs)
*/
@ -109,21 +153,13 @@ public class MISession extends Observable {
postCommand(cmd, cmdTimeout);
}
public void setCommandTimeout(long timeout) {
cmdTimeout = timeout;
}
public long getCommandTimeout() {
return cmdTimeout;
}
/**
*
* Sends a command to gdb.
*/
public void postCommand(Command cmd, long timeout) throws MIException {
if (!txThread.isAlive()) {
throw new MIException("TxThread terminated");
if (!txThread.isAlive() || !rxThread.isAlive()) {
throw new MIException("{R,T}xThread terminated");
}
txQueue.addCommand(cmd);
synchronized (cmd) {
@ -139,24 +175,94 @@ public class MISession extends Observable {
}
}
/**
* Close the MISession.
*/
public void terminate() {
// Closing the channel will kill the RxThread.
try {
inChannel.close();
} catch (IOException e) {
}
inChannel = null;
try {
outChannel.close();
} catch (IOException e) {
}
outChannel = null; // This is needed to stop the txThread.
try {
if (txThread.isAlive()) {
txThread.interrupt();
}
txThread.join();
} catch (InterruptedException e) {
}
try {
if (rxThread.isAlive()) {
rxThread.interrupt();
}
rxThread.join();
} catch (InterruptedException e) {
}
}
/**
* The session is in STOPPED state.
* It means the 'run/-exec-run' command was not issued.
* Or the program exited, via a signal or normally.
* It is not the same as gdb/MI *stopped async-class
* gdb/MI stopped means suspended here.
*/
public boolean isStopped() {
return state == STOPPED;
}
/**
* The session is in SUSPENDED state.
* State after hitting a breakpoint or after attach.
*/
public boolean isSuspended() {
return state == SUSPENDED;
}
/**
* The session is in RUNNING state.
*/
public boolean isRunning() {
return state == RUNNING;
}
void setStopped() {
/**
* Set the state STOPPED.
*/
public void setStopped() {
state = STOPPED;
}
void setRunning() {
/**
* Set the state SUSPENDED.
*/
public void setSuspended() {
state = SUSPENDED;
}
/**
* Set the state STOPPED.
*/
public void setRunning() {
state = RUNNING;
}
public void setDirty() {
/**
* Notify the observers of new MI OOB events.
*/
public void notifyObservers(Object arg) {
setChanged();
super.notifyObservers(arg);
}
Queue getTxQueue() {

View file

@ -3,6 +3,7 @@ package org.eclipse.cdt.debug.mi.core;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
@ -15,12 +16,19 @@ import org.eclipse.cdt.debug.mi.core.event.MIFunctionFinishedEvent;
import org.eclipse.cdt.debug.mi.core.event.MISignalEvent;
import org.eclipse.cdt.debug.mi.core.event.MIStepEvent;
import org.eclipse.cdt.debug.mi.core.event.MIWatchpointEvent;
import org.eclipse.cdt.debug.mi.core.output.MIAsyncRecord;
import org.eclipse.cdt.debug.mi.core.output.MIConsoleStreamOutput;
import org.eclipse.cdt.debug.mi.core.output.MIConst;
import org.eclipse.cdt.debug.mi.core.output.MIExecAsyncOutput;
import org.eclipse.cdt.debug.mi.core.output.MILogStreamOutput;
import org.eclipse.cdt.debug.mi.core.output.MINotifyAsyncOutput;
import org.eclipse.cdt.debug.mi.core.output.MIOOBRecord;
import org.eclipse.cdt.debug.mi.core.output.MIOutput;
import org.eclipse.cdt.debug.mi.core.output.MIResult;
import org.eclipse.cdt.debug.mi.core.output.MIResultRecord;
import org.eclipse.cdt.debug.mi.core.output.MIStatusAsyncOutput;
import org.eclipse.cdt.debug.mi.core.output.MIStreamRecord;
import org.eclipse.cdt.debug.mi.core.output.MITargetStreamOutput;
import org.eclipse.cdt.debug.mi.core.output.MIValue;
/*
@ -29,7 +37,6 @@ import org.eclipse.cdt.debug.mi.core.output.MIValue;
*/
public class RxThread extends Thread {
final MISession session;
@ -37,7 +44,6 @@ public class RxThread extends Thread {
public RxThread(MISession s) {
super("MI RX Thread");
session = s;
setDaemon(true);
}
/*
@ -52,7 +58,14 @@ public class RxThread extends Thread {
while (true) {
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("(gdb)")) {
// Testing on GNU/Linux where target stream output
// is entertwine with MI out,
// comment out the if/else below and just use:
// processMIOutput(line);
// at least for testing.
// We accumulate until we see the gdb terminator.
if (line.startsWith(MIOutput.terminator)) {
// discard termination
processMIOutput(buffer.toString());
buffer = new StringBuffer();
@ -62,7 +75,7 @@ public class RxThread extends Thread {
}
}
} catch (IOException e) {
e.printStackTrace();
//e.printStackTrace();
}
}
@ -85,7 +98,7 @@ public class RxThread extends Thread {
String state = rr.getResultClass();
if ("running".equals(state)) {
session.setRunning();
} else {
} else if ("exit".equals(state)) {
session.setStopped();
}
@ -121,27 +134,81 @@ public class RxThread extends Thread {
* Dispatch a thread to deal with the listeners.
*/
void processMIOOBRecord(MIOOBRecord oob, List list) {
if (oob instanceof MIExecAsyncOutput) {
MIExecAsyncOutput exec = (MIExecAsyncOutput)oob;
if (oob instanceof MIAsyncRecord) {
processMIOOBRecord((MIAsyncRecord)oob, list);
} else if (oob instanceof MIStreamRecord) {
processMIOOBRecord((MIStreamRecord)oob);
}
}
void processMIOOBRecord(MIAsyncRecord async, List list) {
if (async instanceof MIExecAsyncOutput) {
MIExecAsyncOutput exec = (MIExecAsyncOutput)async;
// Change of state.
String state = exec.getAsyncClass();
if ("stopped".equals(state)) {
session.setStopped();
session.setSuspended();
}
MIResult[] results = exec.getMIResults();
for (int i = 0; i < results.length; i++) {
String var = results[i].getVariable();
MIValue value = results[i].getMIValue();
MIValue val = results[i].getMIValue();
if (var.equals("reason")) {
if (value instanceof MIConst) {
String reason = ((MIConst)value).getString();
if (val instanceof MIConst) {
String reason = ((MIConst)val).getString();
MIEvent e = createEvent(reason, exec);
if (e != null) {
list.add(e);
}
}
}
}
} else if (async instanceof MIStatusAsyncOutput) {
// Nothing done .. but what about +download??
} else if (async instanceof MINotifyAsyncOutput) {
// Nothing
}
}
void processMIOOBRecord(MIStreamRecord stream) {
if (stream instanceof MIConsoleStreamOutput) {
OutputStream console = session.getConsoleStream();
if (console != null) {
MIConsoleStreamOutput out = (MIConsoleStreamOutput)stream;
String str = out.getString();
if (str != null) {
try {
console.write(str.getBytes());
console.flush();
} catch (IOException e) {
}
}
}
} else if (stream instanceof MITargetStreamOutput) {
OutputStream target = session.getTargetStream();
if (target != null) {
MITargetStreamOutput out = (MITargetStreamOutput)stream;
String str = out.getString();
if (str != null) {
try {
target.write(str.getBytes());
target.flush();
} catch (IOException e) {
}
}
}
} else if (stream instanceof MILogStreamOutput) {
OutputStream log = session.getLogStream();
if (log != null) {
MILogStreamOutput out = (MILogStreamOutput)stream;
String str = out.getString();
if (str != null) {
try {
log.write(str.getBytes());
log.flush();
} catch (IOException e) {
}
}
}
@ -184,38 +251,45 @@ public class RxThread extends Thread {
} else if (rr != null) {
event = new MIBreakpointEvent(rr);
}
session.setSuspended();
} else if ("watchpoint-trigger".equals(reason)) {
if (exec != null) {
event = new MIWatchpointEvent(exec);
} else if (rr != null) {
event = new MIWatchpointEvent(rr);
}
session.setSuspended();
} else if ("end-stepping-range".equals(reason)) {
if (exec != null) {
event = new MIStepEvent(exec);
} else if (rr != null) {
event = new MIStepEvent(rr);
}
session.setSuspended();
} else if ("signal-received".equals(reason)) {
if (exec != null) {
event = new MISignalEvent(exec);
} else if (rr != null) {
event = new MISignalEvent(rr);
}
session.setStopped();
} else if ("location-reached".equals(reason)) {
if (exec != null) {
event = new MISignalEvent(exec);
} else if (rr != null) {
event = new MISignalEvent(rr);
}
session.setSuspended();
} else if ("function-finished".equals(reason)) {
if (exec != null) {
event = new MIFunctionFinishedEvent(exec);
} else if (rr != null) {
event = new MIFunctionFinishedEvent(rr);
}
session.setSuspended();
} else if ("exited-normally".equals(reason)) {
event = new MIExitEvent();
session.setStopped();
}
return event;
}

View file

@ -19,7 +19,6 @@ public class TxThread extends Thread {
super("MI TX Thread");
session = s;
token = 1;
setDaemon(true);
}
public void run () {
@ -30,7 +29,11 @@ public class TxThread extends Thread {
// removeCommand() will block until a command is available.
try {
cmd = txQueue.removeCommand();
} catch (Exception e) {
} catch (InterruptedException e) {
// signal by the session of time to die.
if (session.getChannelOutputStream() == null) {
throw new IOException();
}
//e.printStackTrace();
}

View file

@ -22,7 +22,6 @@ public class EventThread extends Thread {
/*
*/
public void run () {
session.setDirty();
session.notifyObservers(events);
}
}

View file

@ -44,7 +44,7 @@ public class MIArg {
for (int i = 0; i < results.length; i++) {
MIValue value = results[i].getMIValue();
if (value instanceof MIConst) {
String str = ((MIConst)value).getString();
String str = ((MIConst)value).getCString();
aList.add(new MIArg(str, ""));
}
}
@ -63,7 +63,7 @@ public class MIArg {
String aName = "";
MIValue value = args[0].getMIValue();
if (value != null && value instanceof MIConst) {
aName = ((MIConst)value).getString();
aName = ((MIConst)value).getCString();
} else {
aName = "";
}
@ -72,7 +72,7 @@ public class MIArg {
String aValue = "";
value = args[1].getMIValue();
if (value != null && value instanceof MIConst) {
aValue = ((MIConst)value).getString();
aValue = ((MIConst)value).getCString();
} else {
aValue = "";
}

View file

@ -72,7 +72,7 @@ public class MIAsm {
}
if (value != null && value instanceof MIConst) {
str = ((MIConst)value).getString();
str = ((MIConst)value).getCString();
}
if (var.equals("address")) {

View file

@ -66,7 +66,7 @@ public class MIBreakPoint {
MIValue value = results[i].getMIValue();
String str = "";
if (value != null && value instanceof MIConst) {
str = ((MIConst)value).getString();
str = ((MIConst)value).getCString();
}
if (var.equals("number")) {

View file

@ -17,10 +17,70 @@ public class MIConst extends MIValue {
* Translate gdb c-string.
*/
public String getString() {
return cstring;
return getString(cstring);
}
public static String getString(String str) {
StringBuffer buffer = new StringBuffer();
boolean escape = false;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c == '\\') {
if (escape) {
buffer.append(c);
escape = false;
} else {
escape = true;
}
} else {
if (escape) {
buffer.append(isoC(c));
} else {
buffer.append(c);
}
escape = false;
}
}
// If escape is still true it means that the
// last char was an '\'.
if (escape) {
buffer.append('\\');
}
return buffer.toString();
}
public String toString() {
return getString();
return getCString();
}
/**
* Assuming that the precedent character was the
* escape sequence '\'
*/
private static char isoC(char c) {
if (c == '"') {
c = '"';
} else if (c == '\'') {
c = '\'';
} else if (c == '?') {
c = '?';
} else if (c == 'a') {
c = 7;
} else if (c == 'b') {
c = '\b';
} else if (c == 'f') {
c = '\f';
} else if (c == 'n') {
c = '\n';
} else if (c == 'r') {
c = '\r';
} else if (c == 't') {
c = '\t';
} else if (c == 'v') {
c = 11;
}
return c;
}
}

View file

@ -31,7 +31,7 @@ public class MIDataEvaluateExpressionInfo extends MIInfo{
if (var.equals("value")) {
MIValue value = results[i].getMIValue();
if (value instanceof MIConst) {
expr = ((MIConst)value).getString();
expr = ((MIConst)value).getCString();
}
}
}

View file

@ -52,7 +52,7 @@ public class MIDataListChangedRegistersInfo extends MIInfo {
MIValue[] values = list.getMIValues();
for (int i = 0; i < values.length; i++) {
if (values[i] instanceof MIConst) {
String str = ((MIConst)values[i]).getString();
String str = ((MIConst)values[i]).getCString();
if (str != null && str.length() > 0) {
aList.add(str);
}

View file

@ -45,7 +45,7 @@ public class MIDataListRegisterNamesInfo extends MIInfo {
MIValue[] values = list.getMIValues();
for (int i = 0; i < values.length; i++) {
if (values[i] instanceof MIConst) {
String str = ((MIConst)values[i]).getString();
String str = ((MIConst)values[i]).getCString();
if (str != null && str.length() > 0) {
aList.add(str);
}

View file

@ -105,7 +105,7 @@ public class MIDataReadMemoryInfo extends MIInfo {
MIValue value = results[i].getMIValue();
String str = "";
if (value != null && value instanceof MIConst) {
str = ((MIConst)value).getString();
str = ((MIConst)value).getCString();
}
if (var.equals("addr")) {

View file

@ -53,7 +53,7 @@ public class MIFrame {
MIValue value = results[i].getMIValue();
String str = "";
if (value != null && value instanceof MIConst) {
str = ((MIConst)value).getString();
str = ((MIConst)value).getCString();
}
if (var.equals("level")) {

View file

@ -64,7 +64,7 @@ public class MIInfo {
if (var.equals("msg")) {
MIValue value = results[i].getMIValue();
if (value instanceof MIConst) {
String s = ((MIConst)value).getString();
String s = ((MIConst)value).getCString();
return s;
}
}

View file

@ -47,7 +47,7 @@ public class MIMemory {
MIValue value = results[i].getMIValue();
String str = "";
if (value != null && value instanceof MIConst) {
str = ((MIConst)value).getString();
str = ((MIConst)value).getCString();
}
if (var.equals("addr")) {
@ -70,7 +70,7 @@ public class MIMemory {
data = new long[values.length];
for (int i = 0; i < values.length; i++) {
if (values[i] instanceof MIConst) {
String str = ((MIConst)values[i]).getString();
String str = ((MIConst)values[i]).getCString();
try {
data[i] = Long.decode(str.trim()).longValue();
} catch (NumberFormatException e) {

View file

@ -117,8 +117,8 @@ public class MIParser {
if (token.charAt(0) == '^') {
token.deleteCharAt(0);
rr = processMIResultRecord(token, id);
//} else if(token.startsWith(MIOutput.terminator)) {
// break;
} else if(token.toString().startsWith(MIOutput.terminator)) {
break;
} else {
MIOOBRecord band = processMIOOBRecord(token, id);
if (band != null) {
@ -137,7 +137,7 @@ public class MIParser {
/**
* Assuming '^' was deleted.
*/
MIResultRecord processMIResultRecord(StringBuffer buffer, int id) {
private MIResultRecord processMIResultRecord(StringBuffer buffer, int id) {
MIResultRecord rr = new MIResultRecord();
rr.setToken(id);
if (buffer.toString().startsWith(MIResultRecord.DONE)) {
@ -171,7 +171,7 @@ public class MIParser {
/**
*/
MIOOBRecord processMIOOBRecord(StringBuffer buffer, int id) {
private MIOOBRecord processMIOOBRecord(StringBuffer buffer, int id) {
MIOOBRecord oob = null;
char c = buffer.charAt(0);
if (c == '*' || c == '+' || c == '=') {
@ -220,6 +220,10 @@ public class MIParser {
stream = new MILogStreamOutput();
break;
}
// translateCString() assumes that the leading " is deleted
if (buffer.length() > 0 && buffer.charAt(0) == '"') {
buffer.deleteCharAt(0);
}
stream.setCString(translateCString(buffer));
oob = stream;
}
@ -229,7 +233,7 @@ public class MIParser {
/**
* Assuming that the usual leading comma was consume.
*/
MIResult[] processMIResults(StringBuffer buffer) {
private MIResult[] processMIResults(StringBuffer buffer) {
List aList = new ArrayList();
MIResult result = processMIResult(buffer);
if (result != null) {
@ -249,7 +253,7 @@ public class MIParser {
* Construct the MIResult. Characters will be consume/delete
* has moving forward constructing the AST.
*/
MIResult processMIResult(StringBuffer buffer) {
private MIResult processMIResult(StringBuffer buffer) {
MIResult result = new MIResult();
int equal;
if (buffer.length() > 0 && Character.isLetter(buffer.charAt(0))
@ -270,7 +274,7 @@ public class MIParser {
/**
* Find a MIValue implementation or return null.
*/
MIValue processMIValue(StringBuffer buffer) {
private MIValue processMIValue(StringBuffer buffer) {
MIValue value = null;
if (buffer.length() > 0) {
if (buffer.charAt(0) == '{') {
@ -294,7 +298,7 @@ public class MIParser {
* go to the closing '}' consuming/deleting all the characters.
* This is usually call by processMIvalue();
*/
MIValue processMITuple(StringBuffer buffer) {
private MIValue processMITuple(StringBuffer buffer) {
MITuple tuple = new MITuple();
MIResult[] results = null;
// Catch closing '}'
@ -315,7 +319,7 @@ public class MIParser {
* Assuming the leading '[' was deleted, find the closing
* ']' consuming/delete chars from the StringBuffer.
*/
MIValue processMIList(StringBuffer buffer) {
private MIValue processMIList(StringBuffer buffer) {
MIList list = new MIList();
List valueList = new ArrayList();
List resultList = new ArrayList();
@ -345,7 +349,7 @@ public class MIParser {
return list;
}
String translateCString(StringBuffer buffer) {
private String translateCString(StringBuffer buffer) {
boolean escape = false;
boolean closingQuotes = false;
@ -356,14 +360,14 @@ public class MIParser {
char c = buffer.charAt(index);
if (c == '\\') {
if (escape) {
sb.append('\\').append(c);
sb.append(c);
escape = false;
} else {
escape = true;
}
} else if (c == '"') {
if (escape) {
sb.append('\\').append(c);;
sb.append(c);;
escape = false;
} else {
// Bail out.

View file

@ -61,7 +61,7 @@ public class MIRegisterValue {
String aName = "";
MIValue value = args[0].getMIValue();
if (value != null && value instanceof MIConst) {
aName = ((MIConst)value).getString();
aName = ((MIConst)value).getCString();
} else {
aName = "";
}
@ -70,7 +70,7 @@ public class MIRegisterValue {
String aValue = "";
value = args[1].getMIValue();
if (value != null && value instanceof MIConst) {
aValue = ((MIConst)value).getString();
aValue = ((MIConst)value).getCString();
} else {
aValue = "";
}

View file

@ -28,7 +28,7 @@ public class MIStackInfoDepthInfo extends MIInfo {
if (var.equals("depth")) {
MIValue val = results[i].getMIValue();
if (val instanceof MIConst) {
String str = ((MIConst)val).getString();
String str = ((MIConst)val).getCString();
try {
depth = Integer.parseInt(str.trim());
} catch (NumberFormatException e) {

View file

@ -14,6 +14,10 @@ public abstract class MIStreamRecord extends MIOOBRecord {
cstring = str;
}
public String getString () {
return MIConst.getString(getCString());
}
public String toString() {
if (this instanceof MIConsoleStreamOutput) {
return "~\"" + cstring + "\"\n";

View file

@ -47,7 +47,7 @@ public class MIThreadListIdsInfo extends MIInfo {
if (var.equals("thread-id")) {
MIValue value = results[i].getMIValue();
if (value instanceof MIConst) {
String str = ((MIConst)value).getString();
String str = ((MIConst)value).getCString();
try {
threadIds[i] = Integer.parseInt(str.trim());
} catch (NumberFormatException e) {

View file

@ -38,7 +38,7 @@ public class MIThreadSelectInfo extends MIInfo {
if (var.equals("new-thread-ids")) {
MIValue value = results[i].getMIValue();
if (value instanceof MIConst) {
String str = ((MIConst)value).getString();
String str = ((MIConst)value).getCString();
try {
threadId = Integer.parseInt(str.trim());
} catch (NumberFormatException e) {