I am developing a compiler (with JavaCC) for QBasic language and I have an issue relate to Error Recovery (Error Recovery is showing all compiler errors when you compile the program)
so I had to handle ParseException and ignore the line where ParseException occurs
note : QBasic language has no semicolons so every statement has a separated line
I have tried to try catch the ParseException in every statement and handle it by using getNextToken repeatedly until I have "\n" token
unfortunately that does not work !!
Here is my program method :
void program():
{
Node n =null;
programNode ret = new programNode() ;
boolean canrun=true;
}
{
(< LINE > | < SPACE >)*
(
try {
n = statement()(< SPACE >)* <LINE>
}
catch(ParseException e)
{
canrun=false;
Excep.add(e);
Token t;
do
{
t=CodeParserTokenManager.getNextToken();
}while (t.image!="\n");
}
(< LINE > | < SPACE >)*{
if (n!=null)
ret.addChild(n);
})+ "?"
{
if (canrun)
ret.Start();
}
}
And here is my Parser class :
PARSER_BEGIN(CodeParser)
import java.util.ArrayList;
public class CodeParser
{
public static void main(String args[])
{
CodeParser Parser = new CodeParser(System.in);
try {
program() ;
}
catch(ParseException e)
{
}
}
}
PARSER_END(CodeParser)
I believe the problem is the line:
}while (t.image!="\n");
because 1) you shouldn't use != with strings, 2) the image could be different ("\r\n" for instance).
Try t.kind!=LINE.
Related
I am using Poco::FileInputStream to design a copy function
void do_copy_file(Poco::FileInputStream & iss)
{
Poco::FileOutputStream fos("output.txt");
Poco::StreamCopier::copyStream(iss, fos);
}
Then, a user can call do_copy_file like this
Poco::FileInputStream fis;
do_copy_file(fis);
My question: Can I judge whether iss refers a valid file?
The Poco::FileOutputStream just throws a Poco::FileException if an error occurs when trying to open it, e.g. if a invalid file path is used. It doesn't have any function to test whether it is valid.
What you could do is change your do_copy_file() function to catch an Poco::FileException exception and return a boolean value - true if opened successfully or false otherwise:
bool do_copy_file(Poco::FileInputStream & iss)
{
bool result(true);
try
{
Poco::FileOutputStream fos("output.txt");
Poco::StreamCopier::copyStream(iss, fos);
}
catch (const Poco::FileException&)
{
result = false;
}
return result;
}
Then you call it like this:
Poco::FileInputStream fis;
if (do_copy_file(fis)
{
//output file stream opened successfully
}
If you want do_copy_file() to catch an exception for opening the input stream I would recommend doing that in the function itself. Instead of passing the input streams pass the file paths instead:
bool do_copy_file(const std::string &inputFile, const std::string& outputFile)
{
bool result(true);
try
{
Poco::FileInputStream fis(inputFile);
Poco::FileOutputStream fos(outputFile);
Poco::StreamCopier::copyStream(fis, fos);
}
catch (const Poco::FileException&)
{
result = false;
}
return result;
}
I am a beginner with JavaCC,and i'm trying to generate a file Parser.
I have already been able to generate a successful parser interpenetrated a line that is entered on the keyboard.
Parser example when I enter the keyboard "First Name: William", I managed to display on the screen the name of the variable and the value.
Now I have a file .txt who contain a large number of names and their value, and I would like to successfully display them on the screen.
below is my .jj file that I have already written to generate a parser of a typed line
Now i want the same but for a file.
options
{
static = true;
}
PARSER_BEGIN(parser_name)
public class parser_name
{
public static void main(String args []) throws ParseException
{
System.out.println("Waiting for the Input:");
parser_name parser = new parser_name(System.in);
parser.Start();
}
}
PARSER_END(parser_name)
SKIP :
{
" "
| "\r"
| "\t"
| "\n"
}
TOKEN : { < DIGIT : (["0"-"9"])+ > }
TOKEN : { <VARIABLE: (["a"-"z", "A"-"Z"])+> }
TOKEN : { <VALUE: (~["\n",":"])+> }
TOKEN : { <ASSIGNMENT: ":"> }
void Start(): { Token t,t1,t2;}
{
t=<VARIABLE>
t1=<ASSIGNMENT>
t2=<VALUE>
{ System.out.println("The Variable is "+t.image+",and the Value is "+t2.image); }
}
I have already tried to replace the "System.in" at the parser constructor with an object of type File.And then read the file by line, but it did not work.
Pass a Reader to the parser's constructor.
I am trying javacc for the first time with a simple naive example which is not working. My BNF is as follows:
<exp>:= <num>"+"<num>
<num>:= <digit> | <digit><num>
<digit>:= [0-9]
Based on this BNF, I am writing the SimpleAdd.jj as follows:
options
{
}
PARSER_BEGIN(SimpleAdd)
public class SimpleAdd
{
}
PARSER_END(SimpleAdd)
SKIP :
{
" "
| "\r"
| "\t"
| "\n"
}
TOKEN:
{
< NUMBER: (["0"-"9"])+ >
}
int expr():
{
int leftValue ;
int rightValue ;
}
{
leftValue = num()
"+"
rightValue = num()
{ return leftValue+rightValue; }
}
int num():
{
Token t;
}
{
t = <NUMBER> { return Integer.parseInt(t.toString()); }
}
using the above file, I am generating the java source classes. My main class is as follows:
public class Main {
public static void main(String [] args) throws ParseException {
SimpleAdd parser = new SimpleAdd(System.in);
int x = parser.expr();
System.out.println(x);
}
}
When I am entering the expression via System.in, I am getting the following error:
11+11^D
Exception in thread "main" SimpleAddTest.ParseException: Encountered "<EOF>" at line 0, column 0.
Was expecting:
<NUMBER> ...
at SimpleAddTest.SimpleAdd.generateParseException(SimpleAdd.java:200)
at SimpleAddTest.SimpleAdd.jj_consume_token(SimpleAdd.java:138)
at SimpleAddTest.SimpleAdd.num(SimpleAdd.java:16)
at SimpleAddTest.SimpleAdd.expr(SimpleAdd.java:7)
at SimpleAddTest.Main.main(Main.java:9)
Any hint to solve the problem ?
Edit Note that this answer answers an earlier version of the question.
When a BNF production uses a nonterminal that returns a result, you can record that result in a variable.
First declare the variables in the declaration part of the BNF production
int expr():
{
int leftValue ;
int rightValue ;
}
{
Second, in the main body of the production, record the results in the variables.
leftValue = num()
"+"
rightValue = num()
Finally, use the values of those variables to compute the result of this production.
{ return leftValue+rightValue; }
}
I want to implement the rule coding in my parser generated by javaCC :
Do not change a loop variable inside a for-loop block.
the Rule Production javacc of for-loop block is :
void MyMethod () : {}
{
"(" Argument () ")" {}
(Statement ()) *
}
void Statement () : {}
{
expressionFOR()
}
void expressionFOR() :{}
{
<For> <id> "= " 1 <to> 100
int J
int kk =SUM( , J)
......
}
thank you very much in advance
Assuming you are using JJTree with MULTI=false and VISITOR=true, you could write a visitor along this line
public void visit(SimpleNode node, Object data) {
if( this is a for loop node ) {
push the for loop variable onto a stack of variables
node.childrenAccept(this, null) ;
pop the stack }
else {
if( this is an assignment statement node
and the target variable is on the stack )
report rule violated
node.childrenAccept(this, null) ;
}
}
This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 8 years ago.
I have to make a program that interacts with the user interface that ask a user for a number and a base to convert to binary, hex, or octo. I made a program that works but when the user types in "0 0", it is suppose to terminate and end the program. My program on the other hand doesn't do that but keep going in the while loop.
Here is the code:
import java.util.*; //for Scanner
public class BaseConversionApp {
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
String combo = numbers(console);
while(combo != "0 0") {
if(combo.length() > 0) { //breaks the string into integers to do math to it
Scanner s = new Scanner(combo);
int count = s.nextInt();
int countSecond = s.nextInt();
s.close();
conversion(count,countSecond);
System.out.println();
//now if it goes 0 0 or
String again = numbers(console);
// conversion(count,countSecond);
}
}
//prompts the user for two numbers and checks if the bases are 16, 8, 2.
public static String numbers(Scanner console) {
String combination = "";
String nothing = "0 0";
System.out.print("Enter an integer and the new base: ");
int integer = console.nextInt();
int base = console.nextInt();
if(base == 16 || base == 2 || base == 8) {
combination = integer + " " + base;
return combination;
} else if (base == 0 && integer == 0){
System.out.println("Good bye!");
return nothing;
} else {
System.out.println("Sorry, that is an invalid base. Please enter 2, 8, or 16
only.");
}
return "";
}
//converts the integers into binary, hexa, or octo.
public static void conversion (int integer, int base) {
//takes cares of the special case if the user wants to know hexidecimal
if(base <= 16) {
String calculations = Integer.toString(integer, base);
if(integer > 0 && base > 0) {
System.out.println(integer + " in binary -> " + Integer.toString(integer,
base));
}
}
}
}
You can't compare strings like that, you have to use the String object's equals() method. So, you should have:
while(!"0 0".equals(combo)) {
...
}
Notice that I've put the constant "0 0" first -- that protects you against combo being null. Otherwise you'd have !combo.equals("0 0"), and if combo were null you'd get a NullPointerException when you try to call equals() on a null value.
Try this code instead. Yours looks complicated. Btw, your code works for me.
import java.util.Scanner;
public class NewClass {
static Scanner inp = new Scanner(System.in);
static String line1 = "";
static String line2 = "";
static String exit = "exit";
public static void main(String[] args) {
System.out.println("Enter int first and then base...");
System.out
.println("Enter the word exit to exit!");
while (true) {
line1 = inp.next();
if (line1.equalsIgnoreCase(exit)) {
break;
}
line2 = inp.next();
try {
conversion(Integer.parseInt(line1), Integer.parseInt(line2));
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
System.out.println("Bye...");
}
public static void conversion(int integer, int base) {
// takes cares of the special case if the user wants to know hexadecimal
if (base <= 16) {
String calculations = Integer.toString(integer, base);
if (integer > 0 && base > 0) {
System.out.println(integer + " in binary -> "
+ Integer.toString(integer, base));
}
}
}
}