Hunt this blog

Showing posts with label Language. Show all posts
Showing posts with label Language. Show all posts

Wednesday, July 8, 2009

How to add a HyperlinkListener to a Java component

Using hypertext and hyperlinks in Java JFC/Swing applications makes them look more like web applications, and that's often a good thing. Here's a quick example of how to add a HyperlinkListener to a component in Java. In this case the component I'm going to use is a JEditorPane.

1. First, create JEditorPane, and place it on a container. I've created an object named
menuEditorPane that is a a JEditorPane
2. Next, set the content type of the JEditorPane to "text/html", like this:

menuEditorPane.setContentType("text/html");

3. Next, set the actual content of the JEditorPane. In my case I've done it in a
method, like this:

void setMenuItems()
{
StringBuffer sb = new StringBuffer();
sb.append("Do the foo action
");
sb.append("Do the bar thing
");
menuEditorPane.setText(sb.toString());
}

4. Import two needed classes, like this:

import javax.swing.event.HyperlinkListener;
import javax.swing.event.HyperlinkEvent;

5. Implement a HyperlinkListener, as shown below. Note that the text you get when you
look at e.getDescription() is the URL of the hyperlink.

class MenuPaneHyperlinkListener implements HyperlinkListener
{
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
StringTokenizer st = new StringTokenizer(e.getDescription(), " ");
if (st.hasMoreTokens()) {
String s = st.nextToken();
System.err.println("token: " + s);
}
}
}
}

6. Add your HyperlinkListener to the JEditorPane, like this:

menuEditorPane.addHyperlinkListener(new MenuPaneHyperlinkListener());

Sunday, July 5, 2009

What Is .NET...?

.NET


The .NET Framework is Microsoft's application development platform that enables developers to easily create Windows applications, web applications, and web services using a myriad of different programming languages, and without having to worry about low-level details like memory management and processor-specific instructions.

The Runtime

At the heart of .NET is the Common Language Runtime, commonly referred to as the CLR. The CLR is made up of a number of different parts, which I will be covering here piece by piece (if you didn't want a technical article then you should've followed the marketing link).

1. Language Independence

One of the most important facets of the .NET Framework is language independence. You can write .NET applications using any number of different programming languages. The most popular languages tend to be C# and VB.NET, but many other languages now have .NET versions including Python, COBOL, and more. You can see a list of many of the languages you can use with .NET over at dotnetpowered.com/languages.aspx.

Language independence is attained through the use of an intermediate language (IL). What this means is that instead of code being compiled in actual machine code (code that the CPU would run), it is instead compiled into a high-level generic language. This means that whatever language you write your code in, when you compile it with .NET it will become IL. Since all languages eventually get translated into the intermediate language, the runtime only has to worry about understanding and working with the intermediate language instead of the plethora of languages that you could actually use to write code.


2. Just-in-Time Compilation

If your mantra is, "Why do something now you can put off till tomorrow?" then you have something in common with the CLR. When you compile your code and it is translated to the intermediate language it is then simply stored in an assembly. When that assembly is used the CLR picks up that code and compiles it on-the-fly for the specific machine that is running the code. This means the runtime could compile the code differently based on what CPU or operating system the application is being run on. However, at this point the CLR doesn't compile everything in the assembly; it only compiles the individual method that is being invoked. This kind of on-the-fly compilation, referred to as jitting, only happens once per method call. The next time a method is called, no compilation occurs because the CLR has already compiled that code.

3. Memory Management

One of the constant assailants on productivity in unmanaged programming platforms is manually managing memory. Having to deal with memory management is also one of the largest sources for bugs and security holes in many applications. .NET removes the hassle of manually managing memory through the use of the aptly named garbage collector. Instead of the developer needing to remove objects from memory, the garbage collector looks at the current objects in memory and then decides which ones aren't needed anymore. For some developers this will be a tough pill to swallow; if you are used to managing memory then turning it over to an automated process can be somewhat troubling. This is when you have to take a step back, stop worrying, and embrace the runtime. There are bigger problems to solve (namely the business problems that are probably the real goal).


Alternative CLR Implementations

The .NET runtime is actually based on a standard developed by Microsoft called the CLI or Common Language Infrastructure, portions of which have been submitted to Ecma as an international standard. Because the CLR is based on an open standard, there have been a number of alternative CLR implementations, most notably Rotor and Mono. Rotor was a project from Microsoft Research, is a version of the CLR that will run on Mac OS, and is shared source. Mono is an independent open source implementation of the CLR that runs on various Linux distributions. While "Write once, run away" is not always realistic with .NET, there are some options available when it comes to other platforms. (Some code can be moved without issue, but most will require some tweaking, as different implementation includes different functionality.)


The Library

While the runtime is definitely the most important part of .NET, you can't do too much with it by itself. This is where the Base Class Library (or BCL) comes in. The BCL includes a lot of the plumbing of .NET, including the system types, IO, and functions for working with text. In addition to the BCL, there is the Framework Class Library (FCL). The FCL is an extended library that makes working with the .NET Framework practical and includes the following major pieces:

Monday, May 25, 2009

Exceptions in C++

Exceptions provide a way to react to exceptional circumstances (like runtime errors) in our program by transferring control to special functions called handlers.

To catch exceptions we must place a portion of code under exception inspection. This is done by enclosing that portion of code in a try block. When an exceptional circumstance arises within that block, an exception is thrown that transfers the control to the exception handler. If no exception is thrown, the code continues normally and all handlers are ignored.

A exception is thrown by using the throw keyword from inside the try block. Exception handlers are declared with the keyword catch, which must be placed immediately after the try block:

// exceptions
#include
using namespace std;

int main () {
try
{
throw 20;
}
catch (int e)
{
cout << "An exception occurred. Exception Nr. " << e << endl;
}
return 0;
}

The code under exception handling is enclosed in a try block. In this example this code simply throws an exception:

throw 20;

A throw expression accepts one parameter (in this case the integer value 20), which is passed as an argument to the exception handler.

The exception handler is declared with the catch keyword. As you can see, it follows immediately the closing brace of the try block. The catch format is similar to a regular function that always has at least one parameter. The type of this parameter is very important, since the type of the argument passed by the throw expression is checked against it, and only in the case they match, the exception is caught.

We can chain multiple handlers (catch expressions), each one with a different parameter type. Only the handler that matches its type with the argument specified in the throw statement is executed.

If we use an ellipsis (...) as the parameter of catch, that handler will catch any exception no matter what the type of the throw exception is. This can be used as a default handler that catches all exceptions not caught by other handlers if it is specified at last:

try {
// code here
}
catch (int param) { cout << "int exception"; }
catch (char param) { cout << "char exception"; }
catch (...) { cout << "default exception"; }

In this case the last handler would catch any exception thrown with any parameter that is neither an int nor a char.

After an exception has been handled the program execution resumes after the try-catch block, not after the throw statement!.

It is also possible to nest try-catch blocks within more external try blocks. In these cases, we have the possibility that an internal catch block forwards the exception to its external level. This is done with the expression throw; with no arguments. For example:

try {
try {
// code here
}
catch (int n) {
throw;
}
}
catch (...) {
cout << "Exception occurred";
}

Monday, May 11, 2009

Prolog grammar parser generator

Prolog has the capacity to load definite clause grammar rules (DCG rules) and automatically convert them to Prolog parsing rules. As an illustration, consider a typical kind of left-regular grammar for the regular language a*bb ...

S --> a S
S --> B
B --> bC
C --> b
For Prolog, rewrite this grammar something like this ...
s1 --> [a], s1.
s1 --> b.

b --> [b,b].
Notice that we have collapsed the last two rules into one. Do not be confused by the use of 'b' as both a nonterminal symbol and as a terminal symbol. In Prolog grammars, any use as a terminal symbol must always be within brackets '[..]'.

When loaded into Prolog, these grammar rules are translated into the following clauses
s1(A,B) :-
'C'(A,a,C),
s1(C,B).
s1(A,B) :- b(A,B).

b([b,b|A],A).
'C' is a built-in Prolog predicate whose intuitive meaning is "connects" and whose definition is ...
'C'([A|B],A,B).
One can use the grammer as a parser ...
?- 'C'([1,2,3],1,[2,3]).
Yes

?- s1([a,a,a,b,b],[]).
Yes

?- s1([a,b[,[]).
No
... but not as a generator ...
?- s1(S,[]).
... (infinite loop)
The use of a Prolog grammar as a generator is uncommon. We will see that most useful grammars are specified for the sake of parsing, not expression generation.

Here is a clause tree, with root s1([a,b,b],[]) ...



Pairs of parameters like [a,b,b] and [], as in the root of the tree are said to "represent differences". Thus, the parameter pair [a,b,b] and [b] represents the difference [a,a].

The reason that the Prolog (left-regular) grammar cannot be used to generate sequences is that the grammar is right-recursive. There could be any number of a's at the beginning of the sequence S, and the first clause for s1 could be used repeatedly. The following derivation reveals the problem ...



Here is an alternate Prolog grammar (in context-free form) for a*bb that could be used also as a generator ...
s_1 --> a, b.

a --> []. % empty production
a --> [a],a.

b --> [b,b].
With this grammar ...
?- s_1(S,[]).
S = [b,b] ;
S = [a,b,b] ;
S = [a,a,b,b] ;
...
By the way, the empty production (2nd grammar rule) will be loaded as the following clause -- which means either consume nothing (when parsing) or generate nothing ...
a(A,A).

Exercise 7.1 Explain why this grammar will generate sequences.

Exercise 7.2 Specify a Prolog grammar for the language of sequences consisting of a's followed by an equal number(zero or more) of b's. Recall that this language is context-free but not regular.


For non-context-free languages one can use Prolog grammars with parameters -- a clever device -- bracketed, embedded, Prolog goals -- for specifying context (or other) information. For example, consider the following Prolog grammar for sequences of equal numbers of a's followed by b's followed by c's ...
s2 --> a(N), b(N), c(N).

a(0) --> [].
a(M) --> [a],
a(N),
{M is N + 1}. % embedded Prolog Goal

b(0) --> [].
b(M) --> [b],
b(N),
{M is N + 1}.

c(0) --> [].
c(M) --> [c],
c(N),
{M is N + 1}.
Exercise 7.1.3 Load the s2 grammar and test is on various inputs, both as parser and generator. Also, look at the Prolog listing so as to see how the embedded goals are handled.

Wednesday, May 6, 2009

JAVA- some string manipulation methods

The String class defines a lot of functions. Here are some that you might find useful. Assume that s1 and s2 refer to values of type String:
s1.equals(s2) is a function that returns a boolean value. It returns true if s1 consists of exactly the same sequence of characters as s2, and returns false otherwise.
s1.equalsIgnoreCase(s2) is another boolean-valued function that checks whether s1 is the same string as s2, but this function considers upper and lower case letters to be equivalent. Thus, if s1 is "cat", then s1.equals("Cat") is false, while s1.equalsIgnoreCase("Cat") is true.
s1.length(), as mentioned above, is an integer-valued function that gives the number of characters in s1.
s1.charAt(N), where N is an integer, returns a value of type char. It returns the N-th character in the string. Positions are numbered starting with 0, so s1.charAt(0) is actually the first character, s1.charAt(1) is the second, and so on. The final position is s1.length() - 1. For example, the value of "cat".charAt(1) is 'a'. An error occurs if the value of the parameter is less than zero or greater than s1.length() - 1.
s1.substring(N,M), where N and M are integers, returns a value of type String. The returned value consists of the characters in s1 in positions N, N+1,..., M-1. Note that the character in position M is not included. The returned value is called a substring of s1.
s1.indexOf(s2) returns an integer. If s2 occurs as a substring of s1, then the returned value is the starting position of that substring. Otherwise, the returned value is -1. You can also use s1.indexOf(ch) to search for a particular character, ch, in s1. To find the first occurrence of x at or after position N, you can use s1.indexOf(x,N).
s1.compareTo(s2) is an integer-valued function that compares the two strings. If the strings are equal, the value returned is zero. If s1 is less than s2, the value returned is a number less than zero, and if s1 is greater than s2, the value returned is some number greater than zero. (If both of the strings consist entirely of lower case letters, then "less than" and "greater than" refer to alphabetical order. Otherwise, the ordering is more complicated.)
s1.toUpperCase() is a String-valued function that returns a new string that is equal to s1, except that any lower case letters in s1 have been converted to upper case. For example, "Cat".toUpperCase() is the string "CAT". There is also a function s1.toLowerCase().
s1.trim() is a String-valued function that returns a new string that is equal to s1 except that any non-printing characters such as spaces and tabs have been trimmed from the beginning and from the end of the string. Thus, if s1 has the value "fred ", then s1.trim() is the string "fred".

Types and Literals in JAVA

A variable in Java is designed to hold only one particular type of data; it can legally hold that type of data and no other. The compiler will consider it to be a syntax error if you try to violate this rule. We say that Java is a strongly typed language because it enforces this rule.

There are eight so-called primitive types built into Java. The primitive types are named byte, short, int, long, float, double, char, and boolean. The first four types hold integers (whole numbers such as 17, -38477, and 0). The four integer types are distinguished by the ranges of integers they can hold. The float and double types hold real numbers (such as 3.6 and -145.99). Again, the two real types are distinguished by their range and accuracy. A variable of type char holds a single character from the Unicode character set. And a variable of type boolean holds one of the two logical values true or false.

Any data value stored in the computer's memory must be represented as a binary number, that is as a string of zeros and ones. A single zero or one is called a bit. A string of eight bits is called a byte. Memory is usually measured in terms of bytes. Not surprisingly, the byte data type refers to a single byte of memory. A variable of type byte holds a string of eight bits, which can represent any of the integers between -128 and 127, inclusive. (There are 256 integers in that range; eight bits can represent 256 -- two raised to the power eight -- different values.) As for the other integer types,
short corresponds to two bytes (16 bits). Variables of type short have values in the range -32768 to 32767.
int corresponds to four bytes (32 bits). Variables of type int have values in the range -2147483648 to 2147483647.
long corresponds to eight bytes (64 bits). Variables of type long have values in the range -9223372036854775808 to 9223372036854775807.

You don't have to remember these numbers, but they do give you some idea of the size of integers that you can work with. Usually, you should just stick to the int data type, which is good enough for most purposes.

The float data type is represented in four bytes of memory, using a standard method for encoding real numbers. The maximum value for a float is about 10 raised to the power 38. A float can have about 7 significant digits. (So that 32.3989231134 and 32.3989234399 would both have to be rounded off to about 32.398923 in order to be stored in a variable of type float.) A double takes up 8 bytes, can range up to about 10 to the power 308, and has about 15 significant digits. Ordinarily, you should stick to the double type for real values.

A variable of type char occupies two bytes in memory. The value of a char variable is a single character such as A, *, x, or a space character. The value can also be a special character such a tab or a carriage return or one of the many Unicode characters that come from different languages. When a character is typed into a program, it must be surrounded by single quotes; for example: 'A', '*', or 'x'. Without the quotes, A would be an identifier and * would be a multiplication operator. The quotes are not part of the value and are not stored in the variable; they are just a convention for naming a particular character constant in a program.

A name for a constant value is called a literal. A literal is what you have to type in a program to represent a value. 'A' and '*' are literals of type char, representing the character values A and *. Certain special characters have special literals that use a backslash, \, as an "escape character". In particular, a tab is represented as '\t', a carriage return as '\r', a linefeed as '\n', the single quote character as '\'', and the backslash itself as '\\'. Note that even though you type two characters between the quotes in '\t', the value represented by this literal is a single tab character.

Numeric literals are a little more complicated than you might expect. Of course, there are the obvious literals such as 317 and 17.42. But there are other possibilities for expressing numbers in a Java program. First of all, real numbers can be represented in an exponential form such as 1.3e12 or 12.3737e-108. The "e12" and "e-108" represent powers of 10, so that 1.3e12 means 1.3 times 1012 and 12.3737e-108 means 12.3737 times 10-108. This format can be used to express very large and very small numbers. Any numerical literal that contains a decimal point or exponential is a literal of type double. To make a literal of type float, you have to append an "F" or "f" to the end of the number. For example, "1.2F" stands for 1.2 considered as a value of type float. (Occasionally, you need to know this because the rules of Java say that you can't assign a value of type double to a variable of type float, so you might be confronted with a ridiculous-seeming error message if you try to do something like "x = 1.2;" when x is a variable of type float. You have to say "x = 1.2F;". This is one reason why I advise sticking to type double for real numbers.)

Even for integer literals, there are some complications. Ordinary integers such as 177777 and -32 are literals of type byte, short, or int, depending on their size. You can make a literal of type long by adding "L" as a suffix. For example: 17L or 728476874368L. As another complication, Java allows octal (base-8) and hexadecimal (base-16) literals. I don't want to cover base-8 and base-16 in detail, but in case you run into them in other people's programs, it's worth knowing a few things: Octal numbers use only the digits 0 through 7. In Java, a numeric literal that begins with a 0 is interpreted as an octal number; for example, the literal 045 represents the number 37, not the number 45. Hexadecimal numbers use 16 digits, the usual digits 0 through 9 and the letters A, B, C, D, E, and F. Upper case and lower case letters can be used interchangeably in this context. The letters represent the numbers 10 through 15. In Java, a hexadecimal literal begins with 0x or 0X, as in 0x45 or 0xFF7A.

Hexadecimal numbers are also used in character literals to represent arbitrary Unicode characters. A Unicode literal consists of \u followed by four hexadecimal digits. For example, the character literal '\u00E9' represents the Unicode character that is an "e" with an acute accent.

For the type boolean, there are precisely two literals: true and false. These literals are typed just as I've written them here, without quotes, but they represent values, not variables. Boolean values occur most often as the values of conditional expressions. For example,
rate > 0.05

is a boolean-valued expression that evaluates to true if the value of the variable rate is greater than 0.05, and to false if the value of rate is not greater than 0.05. As you'll see in Chapter 3, boolean-valued expressions are used extensively in control structures. Of course, boolean values can also be assigned to variables of type boolean.

Java has other types in addition to the primitive types, but all the other types represent objects rather than "primitive" data values. For the most part, we are not concerned with objects for the time being. However, there is one predefined object type that is very important: the type String. A String is a sequence of characters. You've already seen a string literal: "Hello World!". The double quotes are part of the literal; they have to be typed in the program. However, they are not part of the actual string value, which consists of just the characters between the quotes. Within a string, special characters can be represented using the backslash notation. Within this context, the double quote is itself a special character. For example, to represent the string value
I said, "Are you listening!"

with a linefeed at the end, you would have to type the string literal:
"I said, \"Are you listening!\"\n"

You can also use \t, \r, \\, and unicode sequences such as \u00E9 to represent other special characters in string literals. Because strings are objects, their behavior in programs is peculiar in some respects (to someone who is not used to objects). I'll have more to say about them in the next section.

The Java Virtual Machine

Machine language consists of very simple instructions that can be executed directly by the CPU of a computer. Almost all programs, though, are written in high-level programming languages such as Java, Pascal, or C++. A program written in a high-level language cannot be run directly on any computer. First, it has to be translated into machine language. This translation can be done by a program called a compiler. A compiler takes a high-level-language program and translates it into an executable machine-language program. Once the translation is done, the machine-language program can be run any number of times, but of course it can only be run on one type of computer (since each type of computer has its own individual machine language). If the program is to run on another type of computer it has to be re-translated, using a different compiler, into the appropriate machine language.

There is an alternative to compiling a high-level language program. Instead of using a compiler, which translates the program all at once, you can use an interpreter, which translates it instruction-by-instruction, as necessary. An interpreter is a program that acts much like a CPU, with a kind of fetch-and-execute cycle. In order to execute a program, the interpreter runs in a loop in which it repeatedly reads one instruction from the program, decides what is necessary to carry out that instruction, and then performs the appropriate machine-language commands to do so.

One use of interpreters is to execute high-level language programs. For example, the programming language Lisp is usually executed by an interpreter rather than a compiler. However, interpreters have another purpose: they can let you use a machine-language program meant for one type of computer on a completely different type of computer. For example, there is a program called "Virtual PC" that runs on Macintosh computers. Virtual PC is an interpreter that executes machine-language programs written for IBM-PC-clone computers. If you run Virtual PC on your Macintosh, you can run any PC program, including programs written for Windows. (Unfortunately, a PC program will run much more slowly than it would on an actual IBM clone. The problem is that Virtual PC executes several Macintosh machine-language instructions for each PC machine-language instruction in the program it is interpreting. Compiled programs are inherently faster than interpreted programs.)

The designers of Java chose to use a combination of compilation and interpretation. Programs written in Java are compiled into machine language, but it is a machine language for a computer that doesn't really exist. This so-called "virtual" computer is known as the Java virtual machine. The machine language for the Java virtual machine is called Java bytecode. There is no reason why Java bytecode could not be used as the machine language of a real computer, rather than a virtual computer.

However, one of the main selling points of Java is that it can actually be used on any computer. All that the computer needs is an interpreter for Java bytecode. Such an interpreter simulates the Java virtual machine in the same way that Virtual PC simulates a PC computer.

Of course, a different Jave bytecode interpreter is needed for each type of computer, but once a computer has a Java bytecode interpreter, it can run any Java bytecode program. And the same Java bytecode program can be run on any computer that has such an interpreter. This is one of the essential features of Java: the same compiled program can be run on many different types of computers.



Why, you might wonder, use the intermediate Java bytecode at all? Why not just distribute the original Java program and let each person compile it into the machine language of whatever computer they want to run it on? There are many reasons. First of all, a compiler has to understand Java, a complex high-level language. The compiler is itself a complex program. A Java bytecode interpreter, on the other hand, is a fairly small, simple program. This makes it easy to write a bytecode interpreter for a new type of computer; once that is done, that computer can run any compiled Java program. It would be much harder to write a Java compiler for the same computer.

Furthermore, many Java programs are meant to be downloaded over a network. This leads to obvious security concerns: you don't want to download and run a program that will damage your computer or your files. The bytecode interpreter acts as a buffer between you and the program you download. You are really running the interpreter, which runs the downloaded program indirectly. The interpreter can protect you from potentially dangerous actions on the part of that program.

I should note that there is no necessary connection between Java and Java bytecode. A program written in Java could certainly be compiled into the machine language of a real computer. And programs written in other languages could be compiled into Java bytecode. However, it is the combination of Java and Java bytecode that is platform-independent, secure, and network-compatible while allowing you to program in a modern high-level object-oriented language.