   ridiculous
  So I am writing a function, makeAtoms, which iterates a string and adds nodes to a LinkedList which is representative of that string (sort of the opposite of what I was doing in an earlier post).Background Info:- Programming in Java using javac to compileI have a parent class AtomicExpression which has many child classes, such as Number, Variable, SymbolicConstant, BinaryFunction, etc. (It's a math program, derr.) A user enters in a mathematical expression, such as "3+62", and this gets stored as a string.My makeAtoms function needs to turn this string into a LinkedList (yes I am using a list, not a tree, for external reasons, and I won't budge on this!). And so, using the example above, the string would be converted into a Number (3), a BinaryFunction (+), and a Number (62). Hence these would be the nodes of the LinkedList instance.My attempt at the function does compile, but throws all sorts of exceptions, including NullPointerException, at runtime, and most importantly...it doesn't work. I have provided the source for the function at the bottom of this post, but in order to understand what's going on here, let me continue the background info. Also please understand I am just looking for a way to get the function to work and not throw exceptions. If there is a better, more efficient way to skin the cat (which I'm sure there is - obviously I'm not an expert programmer here), then I'm really not interested in suggestions in the design or approach or towards optimizations. If the design I am using can be forced to work, although it may be ugly and inefficient, I am satisfied! [wink]The short term end objective here is to allow input of any non-algebraic, non-relational (no equal '=' or inequality operators) expression, and to have that expression simplified. A separate function other than makeAtoms does the simplifying. Examples of qualifiable input would be:"3+30""24.5838/2.04""3-(-4+-5(5-2))+8"Essentially, input can consist of Numbers (ints or doubles), standard mathematical BinaryFunctions (+,-,*,/,%), and parenthesis for specifying groups (ignore braces and brackets for now). Groups are represented by a class which also extends AtomicExpression called NestedGroup. So for example, in the third example above, the linked list nodes would be Number (3), BinaryFunction (-), NestedGroup (-4+-5(5-2)), BinaryFunction (+), and Number (8). In this case, there is a second set of NestedGroup (5-2) inside the first NestedGroup. I am also not interested in code for input error checking, since I will be the only user of this program anyways. This may be complicated, but the code is given below for reinforcement.This is essential: Every expression, even the simplest one I can think of "1" - which evaluates to itself, is initialized to be inside of a NestedGroup which represents the expression which needs to be solved. NestedGroup has a flag hasBeenResolved (boolean), which signals to the simplifying method to jump out to the next encompassing NestedGroup. Once the main NestedGroup - representing the entire expression - has been resolved, simplify() knows its job is done and may return.And so the solution pattern for the simplify() function is the following:1. Find the innermost nested group (example 3 above is: "5-2").2. Resolve the group and set the flag.3. If certain conditions apply, remove the parenthesis from the nested group.4. Jump either to: the next nested group with the same nest level as the current, or if there are none, to the next outermost nested group. If the next outermost group is the main Nested Group, then the expression is simplified so return.5. Repeat 1 - 4.I am providing all this information because the function is a little cryptic and I really need help with this one guys. For now I only am concerned with the function at hand, makeAtoms, which turns a text string into a generic LinkedList<AtomicExpression>. Without further ado, here is the function, as well as the NestedGroup class definition (for your viewing pleasure). Below the code segment I have provided a step by step walkthrough to help guide you.class NestedGroup extends AtomicExpression{short type;// Identifies the type of group: (), [], or {}byte nestLevel;// Identifies the nest level of groupLinkedList<AtomicExpression> group;// Holds the LinkedList it representsboolean isResolved;// Has it already been resolved or not?static byte numNests = -1;// Independent count of how many nests there// are in the expressionNestedGroup(){type = -1;nestLevel = -2;group = null;isResolved = false;numNests++;}NestedGroup(short t, LinkedList<AtomicExpression> g){numNests++;type = t;nestLevel = numNests;isResolved = false;group = g;}// This is a bad design, see notes in the walkthrough below the code segment.NestedGroup(String str){if(str.equals("POINTER"){type = -1;nestLevel = -2;group = null;isResolved = false;}}LinkedList<AtomicExpression> evaluate(){return group;}}// Inside another class definition{LinkedList<AtomicExpression> makeAtoms(String str){if(str == "" || str == null) return null;LinkedList<AtomicExpression> list = new LinkedList<AtomicExpression>();NestedGroup ng = new NestedGroup();ng.type = 0;ng.nestLevel = 0;ng.group = null;ng.isResolved = false;NestedGroup pointer = new NestedGroup("POINTER");int i;byte numNests = 0;for(i = 0; i < str.length(); i++){if(str.charAt(i) >= '0' && str.charAt(i) <= '9'){int x = (int)(str.charAt(i) - ASCII_OFFSET);if(numNests == 0)ng.group.add(new Number(x));elsepointer.group.add(new Number(x));}else if(str.charAt(i) == '('){numNests++;NestedGroup temp = new NestedGroup();temp.type = 0;temp.nestLevel = numNests;temp.group = null;temp.isResolved = false;ng.group.add(temp);pointer = temp;}else if(str.charAt(i) == ')'){numNests--;if(numNests < 0){printError("Unmatched precedence operators.");return null;}}else if(str.charAt(i) == '/'){if(numNests == 0)ng.group.add(new BinaryFunction(this.DIVISION,null,null,this));elsepointer.group.add(new BinaryFunction(this.DIVISION ,null,null,this));}else if(str.charAt(i) == '%'){if(numNests == 0)ng.group.add(new BinaryFunction(this.MODULATION,null,null,this));elsepointer.group.add(new BinaryFunction(this.DIVISION ,null,null,this));}else if(str.charAt(i) == '*'){if(numNests == 0)ng.group.add(new BinaryFunction(this.MULTIPLICATION,null,null,this));elsepointer.group.add(new BinaryFunction(this.DIVISION ,null,null,this));}else if(str.charAt(i) == '+'){if(numNests == 0)ng.group.add(new BinaryFunction(this.ADDITION,null,null,this));elsepointer.group.add(new BinaryFunction(this.DIVISION ,null,null,this));}else if(str.charAt(i) == '-'){if(numNests == 0)ng.group.add(new BinaryFunction(this.SUBTRACTION,null,null,this));elsepointer.group.add(new BinaryFunction(this.DIVISION ,null,null,this));}else if(str.charAt(i) == ' ')continue;else{printError("Input of " + str.charAt(i) + " resolves to unknown data type.");return null;}}if(numNests != 0){printError("Unmatched precedence operators");return null;}list.add(ng);return list;}}Walkthrough:NestedGroup Class1. The nestLevel member is critical because it is essentially a precedence identifier. The higher a nestLevel that a NestedGroup has, the sooner it will be resolved. Ergo, the main NestedGroup's nestLevel is zero (0), because it is the last to be resolved before simplify() returns.2. The third constructor is a victim of bad design. As you will see in my makeAtoms function, I need an instance of NestedGroup which is, basically, a pointer to the current NestedGroup being operated on. However I don't want this "pointer" to disrupt the static int numNests because the pointer is essentially a "phantom" NestedGroup, whose sole purpose is to tell makeAtom which NestedGroup is the current parent of the nodes. I cannot think of any other way to create a NestedGroup without affecting the static int, so this was my solution. It is sloppy, but it holds for now.makeAtoms Function1. As you can see one of the first things the function does is create the main NestedGroup which will contain the entire expression in its 'group' data member.I also make a NestedGroup 'pointer' which will tell makeAtoms which NestedGroup's group member the nodes should be appended to.Although I am now wondering why I allocate new memory for 'pointer' if it is just going to be a reference to other NestedGroups....What are youre thoughts on this?You'll also take note a a local variable 'numNests' which redundantly keeps track of the number of nested groups the expression contains, in addition to the main NestedGroup's numNests static int member. When the local variable numNests is zero (0), we know that we are dealing with the expression as a whole, not a NestedGroup node that it contains.2. We iterate the string with a simple giant for-loop, character by character. Don't worry about erroneous input for now, I will tend to that later on. For now, the for-loop has a simple conditional branch inside of it, checking for whether the current character is an int (no decimals for now), a binary operator, or one of the parenthesis symbols '(' or ')'. For each of these separate conditons, we performs slightly different tasks.3. If the current character is between 0 and 9, we make a Number object out of it and pass the constructor its value. If numNests equals zero (0), then we can append the Number to the main NestedGroup. Else, we are currently inside of some recursive NestedGroup, currently pointed to by the pointer NestedGroup, and that becomes the referenced object we add the Number to. This method is used in every other conditional statement within the for-loop.4. From here on out you can pretty much follow whats going on.5. Take note that if there are no parenthesis specified, then the only NestedGroup that gets instantiated would be the main one representing the expression as a whole.So after this small thesis has been written, here is where my problems lie:(A) I am getting a ton of NullPointerExceptions at runtime, and plus the function doesn't work.(B) Please tell me that the approach I am using, albeit inefficient, can be forced to work with a little TLC. Please read that last statement in this post before you answer!(C) Am I implementing the 'pointer' NestedGroup in a valid manner, or is this the primary component that is messing me up?I apologize for the length of this post, but without all the detail there would be no way for anyone to help me out. I am a new Java programmer (and programmer in general) so please keep that in mind when you respond.Most importantly, I am fully aware that I am probably going three sides around the barn in this implementation. You may want to see me working with trees, not lists, or maybe you don't like the way I am representing the expressions in NestedGroups. Unfortunately, I have an enormous amount of time, and thousands of lines of code committed to this implementation. The only way I would change would be if someone were to prove to me beyond the reason of a doubt that I absolutely, positively, cannot make the function work using this method.My email: zharvey238@yahoo.comThis is NOT a school project (I'm not in school anymore) but this project is very important to me. Please help me out.zac   
  I'm not going to debug this whole thing for you, but here's one obvious error I found:NestedGroup ng = new NestedGroup();ng.type = 0;ng.nestLevel = 0;ng.group = null; //ng.group is NULL!ng.isResolved = false;NestedGroup pointer = new NestedGroup("POINTER");int i;byte numNests = 0;for(i = 0; i < str.length(); i++){if(str.charAt(i) >= '0' && str.charAt(i) <= '9'){int x = (int)(str.charAt(i) - ASCII_OFFSET);if(numNests == 0)ng.group.add(new Number(x)); //Here you use ng.group when it's null. You have to initialize it first. You also go on to use this variable many more times without ever initializing it.;  Well, I wouldn't say you're going 3 sides around the barn, more like laps really.   Now you've made it plainly clear that you don't want to change your design (which I strongly dis agree with, but will leave that be).  You owe it to yourself to look into compiler design.  What you will very quickly come accross are two languages Lex & Yacc (which have GNU counterparts Flex & Bison), which will allow you to create grammers which will lexically analyse your input then parse it.  The beauty of it is you can simply lex with FLEX then use your exesting implementation, or use FLEX then Bison and your lexing and parsing is completely done (and in a much easier format).  Both Flex and Bison will compile to C/C++, and I'm 99% sure Java.  For more information on these, I strongly suggest you look up the book Lex&Yacc or take a look at the manuals (just search google for GNU Bison or GNU Flex).  Now I'm at work right now, so I'm not going to get into your code to find the problems, but if I get out of work early tonight, I'll take a look, assuming some else hasen't gotten you straightened out.   ;  Kevinator:If I were to replace the statement:ng.group = null;With:ng.group = new LinkedList<AtomicExpression>();Would that solve the major bug? Also, I wouldn't dare ask anyone to debug the whole thing, but you make it sound like there are hundreds of errors. Are there any other major ones (design/implementation aside) that you can bring to surface?Modena_au:Thank you for your suggestion with Lex and Yacc. They seem very helpful to my situation right now, but unfortunately I just don't have the time to invest into learning them for several months, and the problem is I need an immediate solution now. It would be amazing if you could take a quick look at it tonight when you get out of work, but if not no worries - I certainly wouldnt expect that of anybody!   ;  first off, this method is do-able with a fair bit of brute force. that should give you a sigh of relief :)also, it would help if you showed us the stack trace so we know exactly where in the code you get null pointerssample equation: 1+(2+3(4-6)-14)hitting the first group, the count for nests goes up by one and you create a pointer to the group (2+3(4-6)-14)things still work fine but what happens when you hit the inner group? you shift the pointer to this new group (4-6) but you never go back to the (2+3(4-6)-14) group. the '-14' never gets sent to the inner groupthat was an algorithm problem- as mentioned earlier initializing the group variable in the group variable to a linked list will most likely solve a lot of problems.- the way you go about using the pointer is interesting. simply using "NestedGroup pointer;" before the loop is fine, then later, assign it to something like "pointer = temp;". this solution doesn't solve the problem of going back to bigger loops (must switch pointer back to the previous group once ')' is read in) so you'll need to track how dep you've gone in. to do this you can create a linked list of NestedGroup objects such that the first element is the main group, the second element is the first nested group, and so forth   ;  Ok, the first thing I see when looking at your code is the sectionif(str.charAt(i) >= '0' && str.charAt(i) <= '9'){int x = (int)(str.charAt(i) - ASCII_OFFSET);if(numNests == 0)ng.group.add(new Number(x));elsepointer.group.add(new Number(x));}This will only work for positive numbers between 0 and 9.  If you want to add any number, positive or negative, Create an instance of the Double class (upper case D, not the primitave double).  use Double.valueOf(string str) to convert the area of the string to a double.For example, if you have the string strMyString with a value of "My string -3.41 is Pi times -1", you would keep parsing the string, and if you find '-' followed by a digit, or a digit, you would parse in a while loop count forward how many characters are in this number, so for the example given, your first number would start at 10, and end at 14, so then with your Double class, you could get that number by saying: myDouble.valueOf(strMyString.substring(10, 14));Now, that's the major problem I've seen in your code thus far.  Mind you, I've been working long hours lately, and programming all day doesn't exactly leave you with much mental power left in the evenings.If you've made any more progress narrowing down your problem, I might be able to help more though.   ;  Learning the basics of lex and yacc would not take as long as you seem to think. There are some very good tutorials around that can get you going for this sort of application within hours. In fact most beginners tutorials would start out by solving the exact problem you have, i.e. a simple calculator.True, the advanced stuff will take longer to get to grips with, but for what you are doing you really don't need anything beyond a beginners tutorial, which may even take less time to complete than debugging what you have.