⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 app.html

📁 A very small LISP implementation with several packages and demo programs.
💻 HTML
📖 第 1 页 / 共 5 页
字号:
<h4><a name="calc">A Calculator Example</a></h4><p>Now let's forget our "project.l" test file for a moment, and move on to amore substantial and practical, stand-alone, example. Using what we have learnedso far, we want to build a simple bignum calculator. ("bignum" because Pico Lispcan do <i>only</i> bignums)<p>It uses a single form, a single numeric input field, and lots of buttons. Itcan be found in the Pico Lisp distribution in "misc/calc.l", together with adirectly executable wrapper script "misc/calc".<p>To use it, change to the Pico Lisp installation directory, and start it as<p><pre><code>$ misc/calc</code></pre><p>If you want to use it from other directories too, change the two relativepath names in the first line to absolute paths. We recommend symbolic links insome global directories, as described in the <ahref="tut.html#script">Scripting</a> section of the Pico Lisp Tutorial.<p>If you like to get a Pico Lisp prompt for inspection, start it instead as<p><pre><code>$ ./p dbg.l misc/calc.l -main -go</code></pre><p>Then - as before - point your browser to '<code><ahref="http://localhost:8080">http://localhost:8080</a></code>'.<p>The code for the calculator logic and the GUI is rather straightforward. Theentry point is the single function <code>calculator</code>. It is calleddirectly (as described in <a href="#urlSyntax">URL Syntax</a>) as the server'sdefault URL, and implicitly in all POST requests. No further file access isneeded once the calculator is running.<p>Note that for a production application, we inserted an allow-statement (asrecommended by the <a href="#security">Security</a> chapter)<p><pre><code>(allowed NIL "@calculator" "favicon.ico" "lib.css")</code></pre><p>at the beginning of "misc/calc.l". This will restrict external access to thatsingle function.<p>The calculator uses three global variables, <code>*Init</code>,<code>*Accu</code> and <code>*Stack</code>. <code>*Init</code> is a boolean flagset by the operator buttons to indicate that the next digit should initializethe accumulator to zero. <code>*Accu</code> is the accumulator. It is alwaysdisplayed in the numeric input field, accepts user input, and it holds theresults of calculations. <code>*Stack</code> is a push-down stack, holdingpostponed calculations (operators, priorities and intermediate results) withlower-priority operators, while calculations with higher-priority operators areperformed.<p>The function <code>digit</code> is called by the digit buttons, and addsanother digit to the accumulator.<p>The function <code>calc</code> does an actual calculation step. It pops thestack, checks for division by zero, and displays an error alert if necessary.<p><code>operand</code> processes an operand button, accepting a function and apriority as arguments. It compares the priority with that in the top-of-stackelement, and delays the calculation if it is less.<p><code>finish</code> is used to calculate the final result.<p>The <code>calculator</code> function has one numeric input field, with awidth of 60 characters<p><pre><code>         (gui '(+Var +NumField) '*Accu 60)</code></pre><p>The <code>+Var</code> prefix class associates this field with the globalvariable <code>*Accu</code>. All changes to the field will show up in thatvariable, and modification of that variable's value will appear in the field.<p>The <a name="sqrtButton">square root operator button</a> has an<code>+Able</code> prefix class<p><pre><code>         (gui '(+Able +JS +Button) '(ge0 *Accu) (char 8730)            '(setq *Accu (sqrt *Accu)) )</code></pre><p>with an argument expression which checks that the current value in theaccumulator is positive, and disables the button if otherwise.<p>The rest of the form is just an array (grid) of buttons, encapsulating allfunctionality of the calculator. The user can enter numbers into the inputfield, either by using the digit buttons, or by directly typing them in, andperform calculations with the operator buttons. Supported operations areaddition, subtraction, multiplication, division, sign inversion, square root andpower (all in bignum integer arithmetic). The '<code>C</code>' button justclears the accumulator, while the '<code>A</code>' button also clears allpending calculations.<p>All that in 53 lines of code!<p><hr><h3><a name="charts">Charts</a></h3><p>Charts are virtual components, maintaining the internal representation oftwo-dimensional data.<p>Typically, these data are nested lists, database selections, or some kind ofdynamically generated tabular information. Charts make it possible to view themin rows and columns (usually in HTML <a href="#tables">tables</a>), scroll upand down, and associate them with their corresponding visible GUI components.<p>In fact, the logic to handle charts makes up a substantial part of the wholeframework, with large impact on all internal mechanisms. Each GUI component mustknow whether it is part of a chart or not, to be able to handle its contentsproperly during updates and user interactions.<p>Let's assume we want to collect textual and numerical data. We might create atable<p><pre><code>########################################################################(app)(action   (html 0 "Table" "lib.css" NIL      (form NIL         (&lt;table&gt; NIL NIL '((NIL "Text") (NIL "Number"))            (do 4               (&lt;row&gt; NIL                  (gui '(+TextField) 20)                  (gui '(+NumField) 10) ) ) )         (&lt;submit&gt; "Save") ) ) )########################################################################</code></pre><p>with two columns "Text" and "Number", and four rows, each containing a<code>+TextField</code> and a <code>+NumField</code>.<p>You can enter text into the first column, and numbers into the second.Pressing the "Save" button stores these values in the components on the server(or produces an error message if a string in the second column is not a legalnumber).<p>There are two problems with this solution:<p><ol><li>Though you can get at the user input for the individual fields, e.g.<pre><code>: (val> (get *Top 'gui 2))  # Value in the first row, second column-> 123</code></pre>there is no direct way to get the whole data structure as a single list.Instead, you have to traverse all GUI components and collect the data.<li>The user cannot input more than four rows of data, because there is no easyway to scroll down and make space for more.</ol><p>A chart can handle these things:<p><pre><code>########################################################################(app)(action   (html 0 "Chart" "lib.css" NIL      (form NIL         (gui '(+Chart) 2)                         # Inserted a +Chart         (&lt;table&gt; NIL NIL '((NIL "Text") (NIL "Number"))            (do 4               (&lt;row&gt; NIL                  (gui 1 '(+TextField) 20)         # Inserted '1'                  (gui 2 '(+NumField) 10) ) ) )    # Inserted '2'         (&lt;submit&gt; "Save") ) ) )########################################################################</code></pre><p>Note that we inserted a <code>+Chart</code> component before the GUIcomponents which should be managed by the chart. The argument '2' tells thechart that it has to expect two columns.<p>Each component got an index number (here '1' and '2') as the first argumentto <code>gui</code>, indicating the column into which this component should gowithin the chart.<p>Now - if you entered "a", "b" and "c" into the first, and 1, 2, and 3 intothe second column - we can retrieve the chart's complete contents by sending itthe <code>val&gt;</code> message<pre><code>: (val> (get *Top 'chart 1))  # Retrieve the value of the first chart-> (("a" 1) ("b" 2) ("c" 3))</code></pre><p>BTW, a more convenient function is <code>chart</code><pre><code>: (val> (chart))  # Retrieve the value of the current chart-> (("a" 1) ("b" 2) ("c" 3))</code></pre><p><code>chart</code> can be used instead of the above construct when we want toaccess the "current" chart, i.e. the chart most recently processed in thecurrent form.<h4><a name="scrolling">Scrolling</a></h4><p>To enable scrolling, let's also insert two buttons. We use the pre-definedclasses <code>+UpButton</code> and <code>+DnButton</code><p><pre><code>########################################################################(app)(action   (html 0 "Scrollable Chart" "lib.css" NIL      (form NIL         (gui '(+Chart) 2)         (&lt;table&gt; NIL NIL '((NIL "Text") (NIL "Number"))            (do 4               (&lt;row&gt; NIL                  (gui 1 '(+TextField) 20)                  (gui 2 '(+NumField) 10) ) ) )         (gui '(+UpButton) 1)                   # Inserted two buttons         (gui '(+DnButton) 1)         (----)         (&lt;submit&gt; "Save") ) ) )########################################################################</code></pre><p>to scroll down and up a single (argument '1') line at a time.<p>Now it is possible to enter a few rows of data, scroll down, and continue. Itis not necessary (except in the beginning, when the scroll buttons are stilldisabled) to press the "Save" button, because <b>any</b> button in the form willsend changes to the server's internal structures before any action is performed.<h4><a name="putGet">Put and Get Functions</a></h4><p>As we said, a chart is a virtual component to edit two-dimensional data.Therefore, a chart's native data format is a list of lists: Each sublistrepresents a single row of data, and each element of a row corresponds to asingle GUI component.<p>In the example above, we saw a row like<pre><code>   ("a" 1)</code></pre><p>being mapped to<pre><code>   (gui 1 '(+TextField) 20)   (gui 2 '(+NumField) 10)</code></pre><p>Quite often, however, such a one-to-one relationship is not desired. Theinternal data structures may have to be presented in a different form to theuser, and user input may need conversion to an internal representation.<p>For that, a chart accepts - in addition to the "number of columns" argument -two optional function arguments. The first function is invoked to 'put' theinternal representation into the GUI components, and the second to 'get' datafrom the GUI into the internal representation.<p>A typical example is a chart displaying customers in a database. While theinternal representation is a (one-dimensional) list of customer objects, 'put'expands each object to a list with, say, the customer's first and second name,telephone number, address and so on. When the user enters a customer's name,'get' locates the matching object in the database and stores it in the internalrepresentation. In the following, 'put' will in turn expand it to the GUI.<p>For now, let's stick with a simpler example: A chart that holds just a listof numbers, but expands in the GUI to show also a textual form of each number(in German).<p><pre><code>########################################################################(app)(load "lib/zahlwort.l")(action   (html 0 "Numerals" "lib.css" NIL      (form NIL         (gui '(+Init +Chart) (1 5 7) 2            '((N) (list N (zahlwort N)))            car )         (&lt;table&gt; NIL NIL '((NIL "Numeral") (NIL "German"))            (do 4               (&lt;row&gt; NIL                  (gui 1 '(+NumField) 9)                  (gui 2 '(+Lock +TextField) 90) ) ) )         (gui '(+UpButton) 1)         (gui '(+DnButton) 1)         (----)         (&lt;submit&gt; "Save") ) ) )########################################################################</code></pre><p>"lib/zahlwort.l" defines the utility function <code>zahlwort</code>, which isrequired later by the 'put' function. <code>zahlwort</code> accepts a number andreturns its wording in German.<p>Now look at the code<p><pre><code>         (gui '(+Init +Chart) (1 5 7) 2            '((N) (list N (zahlwort N)))            car )</code></pre><p>We prefix the <code>+Chart</code> class with <code>+Init</code>, and pass ita list of numbers <code>(1 5 7)</code> for the initial value of the chart. Then,following the '2' (the chart has two columns), we pass a 'put' function<p><pre><code>            '((N) (list N (zahlwort N)))</code></pre><p>which takes a number and returns a list of that number and its wording, and a'get' function<p><pre><code>            car )</code></pre><p>which in turn accepts such a list and returns a number, which happens to bethe list's first element.<p>You can see from this example that 'get' is the inverse function of 'put'.'get' can be omitted, however, if the chart is read-only (contains no (or onlylocked) input fields).<p>The field in the second column<p><pre><code>                  (gui 2 '(+Lock +TextField) 90) ) ) )</code></pre><p>is locked, because it displays the text generated by 'put', and is notsupposed to accept any user input.<p>When you start up this form in your browser, you'll see three pre-filledlines with "1/eins", "5/f眉nf" and "7/sieben", according to the<code>+Init</code> argument <code>(1 5 7)</code>. Typing a number somewhere intothe first column, and pressing ENTER or one of the buttons, will show a suitabletext in the second column.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -