Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Icon (programming language)
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
==Language== ===Basic syntax=== The Icon language is derived from the [[ALGOL]]-class of [[structured programming]] languages, and thus has syntax similar to [[C (programming language)|C]] or [[Pascal (programming language)|Pascal]]. Icon is most similar to Pascal, using {{code |1=:=}} syntax for assignments, the {{code|procedure}} keyword and similar syntax. On the other hand, Icon uses C-style braces for structuring execution groups, and programs start by running a procedure called {{code|main}}.{{sfn|Griswold|Griswold|2002|p=xv}} In many ways Icon also shares features with most [[scripting language]]s (as well as [[SNOBOL]] and SL5, from which they were taken): variables do not have to be declared, types are cast automatically, and numbers can be converted to strings and back automatically.{{sfn|Griswold|Griswold|2002|p=xvi}} Another feature common to many scripting languages, but not all, is the lack of a line-ending character; in Icon, lines that do not end with a semicolon get ended by an implied semicolon if it makes sense.{{sfn|Griswold|Griswold|2002|p=10}} Procedures are the basic building blocks of Icon programs. Although they use Pascal naming, they work more like C functions and can return values; there is no {{code|function}} keyword in Icon.{{sfn|Griswold|Griswold|2002|p=1}} <syntaxhighlight lang="icon"> procedure doSomething(aString) write(aString) end </syntaxhighlight> ===Goal-directed execution=== One of the key concepts in SNOBOL was that its functions returned the "success" or "failure" as primitives of the language rather than using [[magic number (programming)|magic numbers]] or other techniques.{{sfn|Griswold|Griswold|2002|p=4}}{{sfn|Tratt|2010|p=74}} For example, a function that returns the position of a substring within another string is a common routine found in most language [[runtime system]]s. In [[JavaScript]] to find the position of the word "World" within a [["Hello, World!" program]] would be accomplished with {{code|position {{=}} "Hello, World".indexOf("World")|icon}}, which would return 7 in the variable {{code|position}}. If one instead asks for the {{code|position {{=}} "Hello, World".indexOf("Goodbye")|icon}} the code will "fail", as the search term does not appear in the string. In JavaScript, as in most languages, this will be indicated by returning a magic number, in this case -1.<ref>{{cite web |url=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf |title=Array.prototype.indexOf() |website=MDN Web Docs|date=27 June 2023 }}</ref> In SNOBOL a failure of this sort returns a special value, {{code|&fail}}. SNOBOL's syntax operates directly on the success or failure of the operation, jumping to labelled sections of the code without having to write a separate test. For instance, the following code prints "Hello, world!" five times:<ref name=lane>{{cite web |url=https://try-mts.com/snobol-introduction/ |title= SNOBOL - Introduction |website=Try MTS |date=26 July 2015 |first=Rupert |last=Lane}}</ref> <syntaxhighlight lang=snobol> * SNOBOL program to print Hello World I = 1 LOOP OUTPUT = "Hello, world!" I = I + 1 LE(I, 5) : S(LOOP) END </syntaxhighlight> To perform the loop, the less-than-or-equal operator, {{code|LE}}, is called on the index variable I, and if it {{code|S}}ucceeds, meaning I is less than 5, it branches to the named label {{code|LOOP}} and continues.<ref name=lane/> Icon retained the concept of flow control based on success or failure but developed the language further. One change was the replacement of the labelled {{code|GOTO}}-like branching with block-oriented structures in keeping with the [[structured programming]] style that was sweeping the computer industry in the late 1960s.{{sfn|Griswold|Griswold|1993|p=53}} The second was to allow "failure" to be passed along the call chain so that entire blocks will succeed or fail as a whole. This is a key concept of the Icon language. Whereas in traditional languages one would have to include code to test the success or failure based on [[Boolean logic]] and then branch based on the outcome, such tests and branches are inherent to Icon code and do not have to be explicitly written.{{sfn|Tratt|2010|p=73}} For instance, consider this bit of code written in the [[Java programming language]]. It calls the function {{code|read()}} to read a character from a (previously opened) file, assigns the result to the variable {{code|a}}, and then {{code|write}}s the value of {{code|a}} to another file. The result is to copy one file to another. {{code|read}} will eventually run out of characters to read from the file, potentially on its very first call, which would leave {{code|a}} in an undetermined state and potentially cause {{code|write}} to cause a [[null pointer exception]]. To avoid this, {{code|read}} returns the special value {{code|EOF}} (end-of-file) in this situation, which requires an explicit test to avoid {{code|write}}ing it: <syntaxhighlight lang="java"> while ((a = read()) != EOF) { write(a); } </syntaxhighlight> In contrast, in Icon the {{code|read()}} function returns a line of text or {{code|&fail}}. {{code|&fail}} is not simply an analog of {{code|EOF}}, as it is explicitly understood by the language to mean "stop processing" or "do the fail case" depending on the context. The equivalent code in Icon is:{{sfn|Tratt|2010|p=74}} <syntaxhighlight lang="icon"> while a := read() do write(a) </syntaxhighlight> This means, "as long as read does not fail, call write, otherwise stop".{{sfn|Tratt|2010|p=74}} There is no need to specify a test against the magic number as in the Java example, this is implicit, and the resulting code is simplified. Because success and failure are passed up through the call chain, one can embed function calls within others and they stop when the nested function call fails. For instance, the code above can be reduced to:{{sfn|Griswold|1996|p=2.1}} <syntaxhighlight lang="icon"> while write(read()) </syntaxhighlight> In this version, if the {{code|read}} call fails, the {{code|write}} call fails, and the {{code|while}} stops.{{sfn|Griswold|1996|p=2.1}} Icon's branching and looping constructs are all based on the success or failure of the code inside them, not on an arbitrary Boolean test provided by the programmer. {{code|if}} performs the {{code|then}} block if its "test" returns a value, and performs the {{code|else}} block or moves to the next line if it returns {{code|&fail}}. Likewise, {{code|while}} continues calling its block until it receives a fail. Icon refers to this concept as '''goal-directed execution'''.{{sfn|Griswold|1996|p=1}} It is important to contrast the concept of success and failure with the concept of an [[Exception handling|exception]]; exceptions are unusual situations, not expected outcomes. Fails in Icon are expected outcomes; reaching the end of a file is an expected situation and not an exception. Icon does not have exception handling in the traditional sense, although fail is often used in exception-like situations. For instance, if the file being read does not exist, {{code|read}} fails without a special situation being indicated.{{sfn|Tratt|2010|p=74}} In traditional language, these "other conditions" have no natural way of being indicated; additional magic numbers may be used, but more typically exception handling is used to "throw" a value. For instance, to handle a missing file in the Java code, one might see: <syntaxhighlight lang="java"> try { while ((a = read()) != EOF) { write(a); } } catch (Exception e) { // something else went wrong, use this catch to exit the loop } </syntaxhighlight> This case needs two comparisons: one for EOF and another for all other errors. Since Java does not allow exceptions to be compared as logic elements, as under Icon, the lengthy {{code|try/catch}} syntax must be used instead. Try blocks also impose a performance penalty even if no exception is thrown, a [[distributed cost]] that Icon normally avoids. Icon uses this same goal-directed mechanism to perform traditional Boolean tests, although with subtle differences. A simple comparison like {{code|if a < b then write("a is smaller than b")|icon}} does not mean, "if the conditional expression evaluation results in or returns a true value" as they would under most languages; instead, it means something more like, "if the conditional expression succeeds and does not fail". In this case, the {{code|<}} operator succeeds if the comparison is true. The {{code|if}} calls its {{code|then}} clause if the expression succeeds, and either the {{code|else}} (if present) or the next line if it fails. The result is similar to the traditional if/then seen in other languages, the {{code|if}} performs {{code|then}} if {{code|a}} is less than {{code|b}}. The subtlety is that the same comparison expression can be placed anywhere, for instance: <syntaxhighlight lang="icon"> write(a < b) </syntaxhighlight> Another difference is that the {{code|<}} operator returns its second argument if it succeeds, which in this example will result in the value of {{code|b}} being written if it is larger than {{code|a}}, otherwise nothing is written. As this is not a test ''per se'', but an operator that returns a value, they can be strung together allowing things like {{code|if a < b < c}},{{sfn|Griswold|1996|p=2.1}} a common type of comparison that in most languages must be written as a conjunction of two inequalities like {{code|if (a < b) && (b < c)}}. A key aspect of goal-directed execution is that the program may have to rewind to an earlier state if a procedure fails, a task known as ''backtracking''. For instance, consider code that sets a variable to a starting location and then performs operations that may change the value - this is common in string scanning operations for instance, which will advance a cursor through the string as it scans. If the procedure fails, it is important that any subsequent reads of that variable return the original state, not the state as it was being internally manipulated. For this task, Icon has the ''reversible assignment'' operator, {{code|<-}}, and the ''reversible exchange'', {{code|<->}}. For instance, consider some code that is attempting to find a pattern string within a larger string: <syntaxhighlight lang="icon"> { (i := 10) & (j := (i < find(pattern, inString))) } </syntaxhighlight> This code begins by moving {{code|i}} to 10, the starting location for the search. However, if the {{code|find}} fails, the block will fail as a whole, which results in the value of {{code|i}} being left at 10 as an undesirable [[Side effect (computer science)|side effect]]. Replacing {{code|i :{{=}} 10}} with {{code|i <- 10}} indicates that {{code|i}} should be reset to its previous value if the block fails. This provides an analog of [[Atomic commit|atomicity]] in the execution. ===Generators=== Expressions in Icon may return a single value, for instance, {{code|5 > x}} will evaluate and return x if the value of x is less than 5, otherwise it will fail and return no value. Icon also includes the concept of procedures that do not ''immediately'' return success or failure, and instead return new values every time they are called. These are known as [[generator (computer programming)|''generators'']], and are a key part of the Icon language. Within the parlance of Icon, the evaluation of an expression or function produces a ''result sequence''. A result sequence contains all the possible values that can be generated by the expression or function. When the result sequence is exhausted, the expression or function fails. Icon allows any procedure to return a single value or multiple values, controlled using the {{code|fail}}, {{code|return}} and {{code|suspend}} keywords. A procedure that lacks any of these keywords returns {{code|&fail}}, which occurs whenever execution runs to the {{code|end}} of a procedure. For instance: <syntaxhighlight lang="icon"> procedure f(x) if x > 0 then { return 1 } end </syntaxhighlight> Calling {{code|f(5)}} will return 1, but calling {{code|f(-1)}} will return {{code|&fail}}. This can lead to non-obvious behavior, for instance, {{code|write(f(-1))}} will output nothing because {{code|f}} fails and suspends operation of {{code|write}}.{{sfn|Tratt|2010|p=75}} Converting a procedure to be a generator uses the {{code|suspend}} keyword, which means "return this value, and when called again, start execution at this point". In this respect it is something like a combination of the [[Static (keyword)|{{code|static}}]] concept in C and {{code|return}}. For instance:{{sfn|Tratt|2010|p=74}} <syntaxhighlight lang="icon"> procedure ItoJ(i, j) while i <= j do { suspend i i +:= 1 } fail end </syntaxhighlight> creates a generator that returns a series of numbers starting at {{code|i}} and ending a {{code|j}}, and then returns {{code|&fail}} after that.{{efn|The {{code|fail}} is not ''required'' in this case as it is immediately before the {{code|end}}. It has been added for clarity.}} The {{code|suspend i}} stops execution and returns the value of {{code|i}} without reseting any of the state. When another call is made to the same function, execution picks up at that point with the previous values. In this case, that causes it to perform {{code|i +:{{=}} 1}}, loop back to the start of the while block, and then return the next value and suspend again. This continues until {{code|i <{{=}} j}} fails, at which point it exits the block and calls {{code|fail}}. This allows [[iterator]]s to be constructed with ease.{{sfn|Tratt|2010|p=74}} Another type of generator-builder is the ''alternator'', which looks and operates like the Boolean {{code|or}} operator. For instance: <syntaxhighlight lang="icon"> if y < (x | 5) then write("y=", y) </syntaxhighlight> This appears to say "if y is smaller than x or 5 then...", but is actually a short-form for a generator that returns values until it falls off the end of the list. The values of the list are "injected" into the operations, in this case, {{code|<}}. So in this example, the system first tests y < x, if x is indeed larger than y it returns the value of x, the test passes, and the value of y is written out in the {{code|then}} clause. However, if x is not larger than y it fails, and the alternator continues, performing y < 5. If that test passes, y is written. If y is smaller than neither x or 5, the alternator runs out of tests and fails, the {{code|if}} fails, and the {{code|write}} is not performed. Thus, the value of y will appear on the console if it is smaller than x or 5, thereby fulfilling the purpose of a Boolean {{code|or}}. Functions will not be called unless evaluating their parameters succeeds, so this example can be shortened to: <syntaxhighlight lang="icon"> write("y=", (x | 5) > y) </syntaxhighlight> Internally, the alternator is not simply an {{code|or}} and one can also use it to construct arbitrary lists of values. This can be used to iterate over arbitrary values, like: <syntaxhighlight lang="icon"> every i := (1|3|4|5|10|11|23) do write(i) </syntaxhighlight> As lists of integers are commonly found in many programming contexts, Icon also includes the {{code|to}} keyword to construct ''ad hoc'' integer generators: <syntaxhighlight lang="icon"> every k := i to j do write(k) </syntaxhighlight> which can be shortened: <syntaxhighlight lang="icon"> every write(1 to 10) </syntaxhighlight> Icon is not strongly typed, so the alternator lists can contain different types of items: <syntaxhighlight lang="icon"> every i := (1 | "hello" | x < 5) do write(i) </syntaxhighlight> This writes 1, "hello" and maybe 5 depending on the value of x. Likewise the ''conjunction operator'', {{code|&}}, is used in a fashion similar to a Boolean {{code|and}} operator:{{sfn|Tratt|2010|p=76}} <syntaxhighlight lang="icon"> every x := ItoJ(0,10) & x % 2 == 0 do write(x) </syntaxhighlight> This code calls {{code|ItoJ}} and returns an initial value of 0 which is assigned to x. It then performs the right-hand side of the conjunction, and since {{code|x % 2}} does equal 0, it writes out the value. It then calls the {{code|ItoJ}} generator again which assigns 1 to x, which fails the right-hand-side and prints nothing. The result is a list of every even integer from 0 to 10.{{sfn|Tratt|2010|p=76}} The concept of generators is particularly useful and powerful when used with string operations, and is a major underlying basis for Icon's overall design. Consider the {{code|indexOf}} operation found in many languages; this function looks for one string within another and returns an index of its location, or a magic number if it is not found. For instance: <syntaxhighlight lang="java"> s = "All the world's a stage. And all the men and women merely players"; i = indexOf("the", s); write(i); </syntaxhighlight> This will scan the string {{code|s}}, find the first occurrence of "the", and return that index, in this case 4. The string, however, contains two instances of the string "the", so to return the second example an alternate syntax is used: <syntaxhighlight lang="java"> j = indexOf("the", s, i+1); write(j); </syntaxhighlight> This tells it to scan starting at location 5, so it will not match the first instance we found previously. However, there may not be a second instance of "the" -there may not be a first one either- so the return value from {{code|indexOf}} has to be checked against the magic number -1 which is used to indicate no matches. A complete routine that prints out the location of every instance is: <syntaxhighlight lang="java"> s = "All the world's a stage. And all the men and women merely players"; i = indexOf("the", s); while i != -1 { write(i); i = indexOf("the", s, i+1); } </syntaxhighlight> In Icon, the equivalent {{code|find}} is a generator, so the same results can be created with a single line: <syntaxhighlight lang="icon"> s := "All the world's a stage. And all the men and women merely players" every write(find("the", s)) </syntaxhighlight> Of course there are times where one does want to find a string after some point in input, for instance, if scanning a text file that contains a line number in the first four columns, a space, and then a line of text. Goal-directed execution can be used to skip over the line numbers: <syntaxhighlight lang="icon"> every write(5 < find("the", s)) </syntaxhighlight> The position will only be returned if "the" appears after position 5; the comparison will fail otherwise, pass the fail to write, and the write will not occur. The {{code|every}} operator is similar to {{code|while}}, looping through every item returned by a generator and exiting on failure:{{sfn|Tratt|2010|p=75}} <syntaxhighlight lang="icon"> every k := i to j do write(someFunction(k)) </syntaxhighlight> There is a key difference between {{code|every}} and {{code|while}}; {{code|while}} re-evaluates the first result until it fails, whereas {{code|every}} fetches the next value from a generator. {{code|every}} actually injects values into the function in a fashion similar to blocks under [[Smalltalk]]. For instance, the above loop can be re-written this way:{{sfn|Tratt|2010|p=75}} <syntaxhighlight lang="icon"> every write(someFunction(i to j)) </syntaxhighlight> In this case, the values from i to j will be injected into {{code|someFunction}} and (potentially) write multiple lines of output.{{sfn|Tratt|2010|p=75}} ===Collections=== Icon includes several [[Collection (abstract data type)|collection types]] including [[List (abstract data type)|lists]] that can also be used as [[Stack (abstract data type)|stacks]] and [[Queue (abstract data type)|queues]], [[associative array|tables]] (also known as maps or dictionaries in other languages), [[Set (abstract data type)|sets]] and others. Icon refers to these as ''structures''. Collections are inherent generators and can be easily called using the bang syntax. For instance: <syntaxhighlight lang="icon"> lines := [] # create an empty list while line := read() do { # loop reading lines from standard input push(lines, line) # use stack-like syntax to push the line on the list } while line := pop(lines) do { # loop while lines can be popped off the list write(line) # write the line out } </syntaxhighlight> Using the fail propagation as seen in earlier examples, we can combine the tests and the loops: <syntaxhighlight lang="icon"> lines := [] # create an empty list while push(lines, read()) # push until empty while write(pop(lines)) # write until empty </syntaxhighlight> Because the list collection is a generator, this can be further simplified with the bang syntax: <syntaxhighlight lang="icon"> lines := [] every push(lines, !&input) every write(!lines) </syntaxhighlight> In this case, the bang in {{code|write}} causes Icon to return a line of text one by one from the array and finally fail at the end. {{code|&input}} is a generator-based analog of {{code|read}} that reads a line from [[standard input]], so {{code|!&input}} continues reading lines until the file ends. As Icon is typeless, lists can contain any different types of values: <syntaxhighlight lang="icon">aCat := ["muffins", "tabby", 2002, 8]</syntaxhighlight> The items can included other structures. To build larger lists, Icon includes the {{code|list}} generator; {{code|code=i := list(10, "word")}} generates a list containing 10 copies of "word". Like arrays in other languages, Icon allows items to be looked up by position, e.g., {{code|code=weight := aCat[4]}}. [[Array slicing]] is included, allowing new lists to be created out of the elements of other lists, for instance, {{code|aCat :{{=}} Cats[2:4]}} produces a new list called aCat that contains "tabby" and 2002. Tables are essentially lists with arbitrary index keys rather than integers: <syntaxhighlight lang="icon"> symbols := table(0) symbols["there"] := 1 symbols["here"] := 2 </syntaxhighlight> This code creates a table that will use zero as the default value of any unknown key. It then adds two items into the table, with the keys "there" and "here", and values 1 and 2. Sets are also similar to lists but contain only a single member of any given value. Icon includes the {{code|++}} to produce the union of two sets, {{code|**}} the intersection, and {{code|--}} the difference. Icon includes a number of pre-defined "Cset"s, a set containing various characters. There are four standard Csets in Icon, {{code|&ucase}}, {{code|&lcase}}, {{code|&letters}}, and {{code|&digits}}. New Csets can be made by enclosing a string in single quotes, for instance, {{code|vowel :{{=}} 'aeiou'}}. ===Strings=== In Icon, strings are lists of characters. As a list, they are generators and can thus be iterated over using the bang syntax: <syntaxhighlight lang="icon"> every write(!"Hello, world!") </syntaxhighlight> Will print out each character of the string on a separate line. Substrings can be extracted from a string by using a range specification within brackets. A range specification can return a point to a single character, or a [[array slicing|slice]] of the string. Strings can be indexed from either the right or the left. Positions within a string are defined to be '''between''' the characters <sub>1</sub>A<sub>2</sub>B<sub>3</sub>C<sub>4</sub> and can be specified from the right <sub>β3</sub>A<sub>β2</sub>B<sub>β1</sub>C<sub>0</sub> For example, <syntaxhighlight lang="icon"> "Wikipedia"[1] ==> "W" "Wikipedia"[3] ==> "k" "Wikipedia"[0] ==> "a" "Wikipedia"[1:3] ==> "Wi" "Wikipedia"[-2:0] ==> "ia" "Wikipedia"[2+:3] ==> "iki" </syntaxhighlight> Where the last example shows using a length instead of an ending position The subscripting specification can be used as a [[value (computer science)#lrvalue|lvalue]] within an expression. This can be used to insert strings into another string or delete parts of a string. For example: <syntaxhighlight lang="icon"> s := "abc" s[2] := "123" s now has a value of "a123c" s := "abcdefg" s[3:5] := "ABCD" s now has a value of "abABCDefg" s := "abcdefg" s[3:5] := "" s now has a value of "abefg" </syntaxhighlight> ===String scanning=== A further simplification for handling strings is the ''scanning'' system, invoked with {{code|?}}, which calls functions on a string: <syntaxhighlight lang="icon"> s ? write(find("the")) </syntaxhighlight> Icon refers to the left-hand-side of the {{code|?}} as the ''subject'', and passes it into string functions. Recall the {{code|find}} takes two parameters, the search text as parameter one and the string to search in parameter two. Using {{code|?}} the second parameter is implicit and does not have to be specified by the programmer. In the common cases when multiple functions are being called on a single string in sequence, this style can significantly reduce the length of the resulting code and improve clarity. Icon function signatures identify the subject parameter in their definitions so the parameter can be [[Loop-invariant code motion|hoisted]] in this fashion. The {{code|?}} is not simply a form of syntactic sugar, it also sets up a "string scanning environment" for any following string operations. This is based on two internal variables, {{code|&subject}} and {{code|&pos}}; {{code|&subject}} is simply a pointer to the original string, while {{code|&pos}} is the current position within it, or cursor. Icon's various string manipulation procedures use these two variables so they do not have to be explicitly supplied by the programmer. For example: <syntaxhighlight lang="icon"> s := "this is a string" s ? write("subject=[",&subject,"], pos=[",&pos,"]") </syntaxhighlight> would produce: <syntaxhighlight lang="text"> subject=[this is a string], pos=[1] </syntaxhighlight> Built-in and user-defined functions can be used to move around within the string being scanned. All of the built-in functions will default to {{code|&subject}} and {{code|&pos}} to allow the scanning syntax to be used. The following code will write all blank-delimited "words" in a string: <syntaxhighlight lang="icon"> s := "this is a string" s ? { # Establish string scanning environment while not pos(0) do { # Test for end of string tab(many(' ')) # Skip past any blanks word := tab(upto(' ') | 0) # the next word is up to the next blank -or- the end of the line write(word) # write the word } } </syntaxhighlight> There are a number of new functions introduced in this example. {{code|pos}} returns the current value of {{code|&pos}}. It may not be immediately obvious why one would need this function and not simply use the value of {{code|&pos}} directly; the reason is that {{code|&pos}} is a variable and thus cannot take on the value {{code|&fail}}, which the procedure {{code|pos}} can. Thus {{code|pos}} provides a lightweight wrapper on {{code|&pos}} that allows Icon's goal-directed flow control to be easily used without having to provide hand-written Boolean tests against {{code|&pos}}. In this case, the test is "is &pos zero", which, in the odd numbering of Icon's string locations, is the end of the line. If it is ''not'' zero, {{code|pos}} returns {{code|&fail}}, which is inverted with the {{code|not}} and the loop continues. {{code|many}} finds one or more examples of the provided Cset parameter starting at the current {{code|&pos}}. In this case, it is looking for space characters, so the result of this function is the location of the first non-space character after {{code|&pos}}. {{code|tab}} moves {{code|&pos}} to that location, again with a potential {{code|&fail}} in case, for instance, {{code|many}} falls off the end of the string. {{code|upto}} is essentially the reverse of {{code|many}}; it returns the location immediately prior to its provided Cset, which the example then sets the {{code|&pos}} to with another {{code|tab}}. Alternation is used to also stop at the end of a line. This example can be made more robust through the use of a more appropriate "word breaking" Cset which might include periods, commas and other punctuation, as well as other whitespace characters like tab and non-breaking spaces. That Cset can then be used in {{code|many}} and {{code|upto}}. A more complex example demonstrates the integration of generators and string scanning within the language. <syntaxhighlight lang="icon"> procedure main() s := "Mon Dec 8" s ? write(Mdate() | "not a valid date") end # Define a matching function that returns # a string that matches a day month dayofmonth procedure Mdate() # Define some initial values static dates static days initial { days := ["Mon","Tue","Wed","Thr","Fri","Sat","Sun"] months := ["Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec"] } every suspend (retval <- tab(match(!days)) || # Match a day =" " || # Followed by a blank tab(match(!months)) || # Followed by the month =" " || # Followed by a blank matchdigits(2) # Followed by at least 2 digits ) & (=" " | pos(0) ) & # Either a blank or the end of the string retval # And finally return the string end # Matching function that returns a string of n digits procedure matchdigits(n) suspend (v := tab(many(&digits)) & *v <= n) & v end </syntaxhighlight>
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)