langscan.c

Go to the documentation of this file.
00001 
00002 /*  $Id: langscan.c 1236 2006-04-09 11:28:08Z andreradke $    */
00003 
00004 /******************************************************************************
00005 
00006     UserLand Frontier(tm) -- High performance Web content management,
00007     object database, system-level and Internet scripting environment,
00008     including source code editing and debugging.
00009 
00010     Copyright (C) 1992-2004 UserLand Software, Inc.
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 
00026 ******************************************************************************/
00027 
00028 #include "frontier.h"
00029 #include "standard.h"
00030 
00031 #include "memory.h"
00032 #include "strings.h"
00033 #include "ops.h"
00034 #include "yytab.h" /*token defines*/
00035 #include "lang.h"
00036 #include "langinternal.h"
00037 #include "langparser.h"
00038 #include "byteorder.h"  /* 2006-04-08 aradke: endianness conversion macros */
00039 
00040 
00041 
00042 #define chstartcomment (byte) chcomment
00043 
00044 #define chendscanstring (byte)0 /*returned when we've run out of text*/
00045 
00046 unsigned long ctscanlines; /*number of lines that have been scanned, for error reporting*/
00047 
00048 unsigned short ctscanchars; /*number of chars passed over on current line, for error reporting*/
00049 
00050 
00051 static Handle hscanstring; /*this is the text that we're parsing*/
00052 
00053 static boolean fllinebasedscan;
00054 
00055 static long ixparsestring; /*index of next character to be returned*/
00056 
00057 static long lenparsestring; /*the number of characters in the parse string*/
00058 
00059 static boolean flsenteol;
00060 
00061 
00062 bigstring bstoken; /*for viewing with the debugger, text of last token*/
00063 
00064 
00065 
00066 
00067 boolean isfirstidentifierchar (byte ch) {
00068     
00069     /*
00070     could this character be the first character in an identifier?
00071     */
00072     
00073     return (isalpha (ch) || (ch == '_'));
00074     
00075     /*
00076         ((ch >= 'a') && (ch <= 'z')) ||
00077 
00078         ((ch >= 'A') && (ch <= 'Z')) ||
00079 
00080         (ch == '_'));
00081     */
00082     } /*isfirstidentifierchar*/
00083     
00084     
00085 boolean isidentifierchar (byte ch) {
00086     
00087     /*
00088     could the character be the second through nth character 
00089     in an identifier?
00090     */
00091     
00092     if (isfirstidentifierchar (ch))
00093         return (true);
00094     
00095     if (isdigit (ch))
00096         return (true);
00097         
00098     if (ch == chtrademark)
00099         return (true);
00100         
00101     return (false);
00102     } /*isidentifierchar*/
00103 
00104 
00105 boolean langisidentifier (bigstring bs) {
00106     
00107     /*
00108     called externally to determine when quoting in necessary in path 
00109     construction
00110     
00111     4.1b2 dmb: check the constants table too
00112     */
00113     
00114     register short ct = stringlength (bs);
00115     register byte *s = bs;
00116     tyvaluerecord val;
00117     hdlhashnode hnode;
00118     
00119     if (ct == 0) /*empty string*/
00120         return (false);
00121     
00122     if (!isfirstidentifierchar (*++s))
00123         return (false);
00124     
00125     while (--ct > 0)
00126         if (!isidentifierchar (*++s))
00127             return (false);
00128     
00129     if (hashtablelookup (hkeywordtable, bs, &val, &hnode)) /*it's a keyword*/
00130         return (false);
00131     
00132     if (hashtablelookup (hconsttable, bs, &val, &hnode)) /*dmb 4.1b2 - it's a constant*/
00133         return (false);
00134     
00135     return (true);
00136     } /*langisidentifier*/
00137 
00138 
00139 
00140 #if (odbengine==0)
00141 static boolean midinsertchar (byte ch, bigstring bs, short ixinsert) {
00142     
00143     byte bs1 [4];  /*rab 3/21/97 was 2*/
00144     
00145     if (ixinsert > lenbigstring)
00146         return (false);
00147     
00148     if (stringlength (bs) == lenbigstring) /*overflow -- push character off end*/
00149         
00150         setstringlength (bs, lenbigstring - 1);
00151     
00152     setstringwithchar (ch, bs1);
00153     
00154     return (midinsertstring (bs1, bs, ixinsert)); /*should always be true*/
00155     } /*midinsertchar*/
00156 
00157 
00158 boolean langdeparsestring (bigstring bs, byte chendquote) {
00159     
00160     /*
00161     add any necessary escape sequences to make the string compilable. 
00162     return true if we don't have to truncate the string to do so.
00163     */
00164     
00165     register byte ch;
00166     register short ix;
00167     register short ct = stringlength (bs);
00168     byte bshex [16]; /*should only need 7 bytes*/
00169     
00170     for (ix = 1; --ct >= 0; ++ix) {
00171         
00172         ch = bs [ix];
00173         
00174         if (isprint (ch)) { /*look for the few printable characters that might need quoting*/
00175             
00176             switch (ch) {
00177                 
00178                 case '\\':
00179                     break;
00180                 
00181                 case '\'':
00182                 case '\"':
00183                 case chclosecurlyquote:
00184                     if (ch != chendquote) /*don't always need to quote these*/
00185                         ch = 0;
00186                     
00187                     break;
00188                     
00189                 default:
00190                     ch = 0;
00191                     
00192                     break;
00193                 }
00194             
00195             if (ch == 0) /*no quote necessary*/
00196                 continue;
00197             }
00198         
00199         if (ch >= 128) /*extended ascii*/
00200             continue;
00201         
00202         if (!midinsertchar ('\\', bs, ix++))
00203             return (false);
00204         
00205         switch (ch) {
00206             
00207             case '\n':
00208                 ch = 'n';
00209                 
00210                 break;
00211             
00212             case '\r':
00213                 ch = 'r';
00214                 
00215                 break;
00216             
00217             case '\t':
00218                 ch = 't';
00219                 
00220                 break;
00221             
00222             case '\\':
00223             case '\'':
00224             case '\"':
00225             case chclosecurlyquote:
00226                 break;
00227             
00228             default:
00229                 if (!midinsertchar ('x', bs, ix++))
00230                     return (false);
00231                 
00232                 numbertohexstring (ch, bshex);
00233                 
00234                 if (!midinsertchar (bshex [5], bs, ix++)) /*skip over 0x00*/
00235                     return (false);
00236                 
00237                 ch = bshex [6];
00238                 
00239                 break;
00240             }
00241         
00242         if (ix > lenbigstring)
00243             return (false);
00244         
00245         bs [ix] = ch;
00246         }
00247     
00248     return (true);
00249     } /*langdeparsestring*/
00250 
00251 
00252 void parsesetscanstring (Handle htext, boolean fllinebased) {
00253     
00254     hscanstring = htext; /*copy into global*/
00255     
00256     fllinebasedscan = fllinebased;
00257     
00258     lenparsestring = gethandlesize (htext);
00259     
00260     ixparsestring = 0;
00261     
00262     ctscanlines = 1;
00263     
00264     ctscanchars = 0;
00265     
00266     flsenteol = false;
00267     } /*parsesetscanstring*/
00268 
00269 
00270 unsigned long parsegetscanoffset (unsigned long ctlines, unsigned short ctchars) {
00271     
00272     /*
00273     convert ctlines/ctchars to a zero-based, absolute offset consistent 
00274     with the parsing of a non-linebased scan string
00275     */
00276     
00277     return (((((unsigned long) ctlines) - 1) << 16) + ctchars);
00278     } /*parsegetscanoffset*/
00279 
00280 
00281 void parsesetscanoffset (unsigned long offset) {
00282     
00283     /*
00284     convert a zero-based, absolute offset to a ctlines/ctchars pair consistent 
00285     with the parsing of a non-linebased scan string, and set our globals to 
00286     that value (for error reporting)
00287     */
00288     
00289     ctscanlines = 1 + (offset >> 16);
00290     
00291     ctscanchars = offset & 0xffff;
00292     } /*parsesetscanoffset*/
00293 
00294 
00295 static boolean parsestringempty (void) {
00296     
00297     return (ixparsestring >= lenparsestring);
00298     } /*parsestringempty*/
00299     
00300     
00301 static byte parsepopchar (void) {
00302     
00303     /*
00304     return the first character from the parse string and remove it
00305     from the string.  if there are no characters in the string we 
00306     return the null character.
00307     
00308     5/7/93 dmb: support non-linebased scans.  instead of returns, we 
00309     start a new "line" when the character count is about to overflow.
00310     
00311     Dave, sorry about the ?: construct -- it's the only one in the product!  :)
00312     */
00313     
00314     register ptrbyte p;
00315     register byte ch;
00316     
00317     if (ixparsestring >= lenparsestring) /*string is empty*/
00318         return (chendscanstring);
00319     
00320     p = (ptrbyte) *hscanstring + ixparsestring++;
00321     
00322     ch = *p;
00323     
00324     ctscanchars++; /*for error reporting*/
00325 
00326 //************ RAB ADDED 10/29/97
00327     if (ixparsestring < lenparsestring) {
00328         p = (ptrbyte) *hscanstring + ixparsestring;
00329         if (*p == chlinefeed) {  //lose it
00330             ++ixparsestring;
00331             ++ctscanchars;
00332             }
00333         }
00334     
00335     if (fllinebasedscan? (ch == chreturn) : (ctscanchars == 0xffff)) { /*passed over another line, or overflowing*/
00336         
00337         ctscanlines++; /*for error reporting*/
00338         
00339         ctscanchars = 0; /*the number of chars we've passed over in the text*/
00340         }
00341     
00342     return (ch);
00343     } /*parsepopchar*/
00344 
00345 
00346 static byte parsefirstchar (void) {
00347     
00348     /*
00349     return the character at the head of the parse stream without 
00350     popping it.
00351     */
00352     
00353     register long ix = ixparsestring;
00354     register ptrbyte p;
00355     
00356     if (ix >= lenparsestring)
00357         return (chendscanstring);
00358 
00359     p = (ptrbyte) *hscanstring + ix;
00360     
00361     return (*p);
00362     } /*parsefirstchar*/
00363     
00364     
00365 static byte parsenextchar (void) {
00366     
00367     /*
00368     return the character at the head of the parse stream without 
00369     popping it.
00370     */
00371     
00372     register long ix = ixparsestring + 1;
00373     register ptrbyte p;
00374     
00375     if (ix >= lenparsestring)
00376         return (chendscanstring);
00377     
00378     p = (ptrbyte) *hscanstring + ix;
00379     
00380     return (*p);
00381     } /*parsenextchar*/
00382 
00383 
00384 static void parsepopidentifier (bigstring bs) {
00385     
00386     /*
00387     pull characters off the front of the input stream as long as
00388     we're still getting identifier characters.  
00389     */
00390     
00391     setstringlength (bs, 0);
00392     
00393     while (true) {
00394         
00395         if (!isidentifierchar (parsefirstchar ())) /*finished accumulating identifier*/
00396             return;
00397         
00398         pushchar (parsepopchar (), bs); /*add char to the end of the string*/
00399         } /*while*/
00400     } /*parsepopidentifier*/
00401 
00402 
00403 static boolean parsepopnumber (tyvaluerecord *val) {
00404     
00405     /*
00406     pull characters off the front of the input stream as long as
00407     we're still getting digits.  when we hit the first non-digit,
00408     convert what we got into a long and return it.
00409     
00410     we expect at least one numeric digit to be there, and do not
00411     provide for an error return.
00412     
00413     5/29/91 dmb: support hex constants in the form "0xhhhhhhhh"
00414     
00415     10/21/91 dmb: detect overly-large numbers, like 999999999999.
00416     */
00417     
00418     bigstring bsnumber;
00419     register boolean flhex = false;
00420     register boolean flfloat = false;
00421     
00422     if (parsefirstchar () == '0') { /*check for hex constant*/
00423         
00424         parsepopchar ();
00425         
00426         if (parsefirstchar () == 'x') {
00427             
00428             parsepopchar ();
00429             
00430             flhex = true;
00431             }
00432         }
00433     
00434     setemptystring (bsnumber);
00435     
00436     while (true) {
00437         
00438         register byte ch = parsefirstchar ();
00439         
00440         if ((ch == '.') && !flfloat)
00441             flfloat = true;
00442         
00443         else {
00444             
00445             if (!isdigit (ch) && !(flhex && isxdigit (ch))) {
00446                 
00447                 if (flfloat) {
00448                     
00449                     double d;
00450                     Handle x;
00451                     
00452                     stringtofloat (bsnumber, &d);
00453                     
00454                     if (!newfilledhandle (&d, longsizeof (d), &x))
00455                         return (false);
00456                     
00457                     initvalue (val, doublevaluetype);
00458                     
00459                     (*val).data.binaryvalue = x;
00460                     }
00461                 else {
00462                     long x;
00463                     bigstring bstest;
00464                     
00465                     if (flhex) {
00466                         
00467                         if (stringlength (bsnumber) > 10)
00468                             goto overflow;
00469                         
00470                         hexstringtonumber (bsnumber, &x);
00471                         }
00472                     else {
00473                         stringtonumber (bsnumber, &x);
00474                         
00475                         popleadingchars (bsnumber, '0');
00476                         
00477                         numbertostring (x, bstest);
00478                         
00479                         popleadingchars (bstest, '0');
00480                         
00481                         if (!equalstrings (bsnumber, bstest))
00482                             goto overflow;
00483                         }
00484                     
00485                     setlongvalue (x, val);
00486                     }
00487                 
00488                 #ifdef fldebug
00489                 
00490                 copystring (bsnumber, bstoken); /*for debugging*/
00491                 
00492                 #endif
00493                 
00494                 return (true);
00495                 }
00496             }
00497         
00498         pushchar (parsepopchar (), bsnumber);
00499         } /*while*/
00500     
00501     overflow:
00502     
00503     langparamerror (numbertoolargeerror, bsnumber);
00504     
00505     return (false);
00506     } /*parsepopnumber*/
00507 
00508 
00509 static byte parsepopescapesequence (void) {
00510     
00511     /*
00512     get the next string character out of the input stream, i.e. a 
00513     character that is part of a string or character constant.  this is 
00514     where we handle backslashes for special characters
00515     */
00516     
00517     register byte ch;
00518     bigstring bs;
00519     long x;
00520     
00521     ch = parsepopchar ();
00522     
00523     switch (ch) {
00524         
00525         case 'n':
00526             return ('\n');
00527         
00528         case 'r':
00529             return ('\r');
00530         
00531         case 't':
00532             return ('\t');
00533         
00534         case '\\':
00535             return ('\\');
00536         
00537         case '\'':
00538             return ('\'');
00539         
00540         case '\"':
00541             return ('\"');
00542         
00543         case 'x':
00544             if (!isxdigit (parsefirstchar ()))
00545                 return (0);
00546             
00547             ch = parsepopchar ();
00548             
00549             setstringwithchar (ch, bs);
00550             
00551             if (isxdigit (parsefirstchar ()))
00552                 pushchar (parsepopchar (), bs);
00553             
00554             hexstringtonumber (bs, &x);
00555             
00556             return ((byte) x);
00557         
00558         default:
00559             return (ch);
00560         }
00561     } /*parsepopescapesequence*/
00562 
00563 
00564 static boolean buildtexthandle (bigstring bs, Handle *htext) {
00565     
00566     /*
00567     5.0.2 dmb: move the characters from bs to the given text handle.
00568     
00569     either create or add to htext.
00570     */
00571     
00572     boolean fl;
00573 
00574     if (*htext == nil)
00575         fl = newtexthandle (bs, htext);
00576     else
00577         fl = pushtexthandle (bs, *htext);
00578     
00579     return (fl);
00580     } /*buildtexthandle*/
00581 
00582 
00583 static boolean parsepopstringconst (Handle *htext) {
00584     
00585     /*
00586     pop a string constant off the front of the input stream and
00587     return a handle to the string allocated in the heap.
00588     
00589     return with an error if the string wasn't properly
00590     terminated, or if there was an allocation error.
00591     
00592     5/6/93: don't allow a string to span input lines
00593     
00594     2.1b2 dmb: handle escape sequences
00595     
00596     2.1b6 dmb: if an escape sequence is for a nul character, we 
00597     can't tell if that's chendscanstring or not; so check for 
00598     that before parsing '\'s.  we'll find out soon enough if we're 
00599     really out of text to scan
00600 
00601     5.0.2 dmb: don't limit string literals to 255 chars; use new 
00602     buildtexthandle for continuation
00603     */
00604     
00605     register byte ch, chstop;
00606     bigstring bs;
00607     unsigned long lnum;
00608     unsigned short cnum;
00609     
00610     chstop = parsepopchar (); /*pop off opening doublequote, our terminator*/
00611     
00612     lnum = ctscanlines;
00613     
00614     cnum = ctscanchars;
00615     
00616     if (chstop == chopencurlyquote)
00617         chstop = chclosecurlyquote;
00618     else
00619         chstop = (byte) '"';
00620     
00621     *htext = nil;
00622 
00623     setstringlength (bs, 0);
00624     
00625     while (true) {
00626         
00627         ch = parsepopchar ();
00628         
00629         if (ch == chstop) /*properly terminated string*/
00630             return (buildtexthandle (bs, htext));
00631         
00632         if (ch == chreturn) /*don't allow string to span lines*/
00633             break;
00634         
00635         if (ch == chendscanstring) /*ran out of characters*/
00636             break;
00637         
00638         if (ch == '\\')
00639             ch = parsepopescapesequence ();
00640         
00641         if (!pushchar (ch, bs)) { /*add the char to the end of the string*/
00642             
00643             if (!buildtexthandle (bs, htext))
00644                 return (false);
00645 
00646             setstringwithchar (ch, bs);
00647             }
00648         } /*while*/
00649     
00650     ctscanlines = lnum; /*make error message point at string start*/
00651     
00652     ctscanchars = cnum;
00653     
00654     langerror (stringnotterminatederror);
00655     
00656     return (false);
00657     } /*parsepopstringconst*/
00658     
00659 
00660 static void parsepopcomment (void) {
00661     
00662     /*
00663     consume characters up to and including the next chendcomment.
00664     
00665     comments cannot span more than one line, so endofline also causes
00666     us to return.
00667     */
00668     
00669     register byte ch;
00670     
00671     while (true) {
00672         
00673         ch = parsepopchar ();
00674         
00675         if ((ch == chendcomment) || (ch == chreturn) || (ch == chendscanstring))
00676             return;
00677         } /*while*/
00678     } /*parsepopcomment*/
00679 
00680 
00681 static boolean parsepopblanks (void) {
00682     
00683     /*
00684     pop all the leading white space.  return false if the input stream is 
00685     empty, true otherwise.
00686 
00687     5.0a12 dmb: handle // comments
00688     */
00689     
00690     register byte ch;
00691     
00692     while (true) {
00693         
00694         if (parsestringempty ())
00695             return (false);
00696         
00697         ch = parsefirstchar ();
00698         
00699         if ((ch == chstartcomment) || (ch == '/' && parsenextchar () == '/')) {
00700             
00701             parsepopcomment (); /*pop everything up to and including endcomment char*/
00702             }
00703             
00704         else {
00705             if ((ch != ' ') && (ch != chtab) && (ch != chreturn))
00706                 return (true);
00707             
00708             parsepopchar (); /*consume a whitespace character*/
00709             }
00710         } /*while*/
00711     } /*parsepopblanks*/
00712     
00713 
00714 static boolean parsepopcharconst (tyvaluerecord *val) {
00715     
00716     /*
00717     pop a character constant in the form of '<char>' off the input
00718     stream.  return with error if there was no char following the 
00719     first ' or if the character immediately following <char> is not another '.
00720     
00721     3/29/91 dmb: handle 4-character ostype constants as well 1-char.
00722     
00723     2.1b2 dmb: handle escape sequences
00724     
00725     2.1b6 dmb: see comment in parsepopstringconst; check for the end 
00726     of the scan string before parsing escape sequences
00727     */
00728     
00729     register byte ch;
00730     register short len = 0;
00731     byte ch4 [4];
00732     OSType osvalue;
00733     unsigned long lnum;
00734     unsigned short cnum;
00735     
00736     parsepopchar (); /*get rid of first single-quote*/
00737     
00738     lnum = ctscanlines;
00739     
00740     cnum = ctscanchars;
00741     
00742     while (true) {
00743         
00744         ch = parsepopchar ();
00745         
00746         if (ch == chsinglequote) { /*end of char const*/
00747             
00748             switch (len) {
00749                 
00750                 case 1: /*normal character const*/
00751                     
00752                     setcharvalue (ch4 [0], val);
00753                     
00754                     #ifdef fldebug
00755                     
00756                     pushchar ((*val).data.chvalue, bstoken); /*for debugging*/
00757                     
00758                     #endif
00759                     
00760                     return (true);
00761                 
00762                 case 4: /*ostype (long) character const*/
00763                     
00764                     moveleft (ch4, &osvalue, 4L);
00765                     
00766                     memtodisklong (osvalue);
00767 
00768                     setostypevalue (osvalue, val);
00769                     
00770                     #ifdef fldebug
00771                     
00772                     ostypetostring (osvalue, bstoken); /*for debugging*/
00773                     
00774                     #endif
00775                     
00776                     return (true);
00777                 
00778                 default:
00779                     goto error;
00780                 }
00781             }
00782         
00783         if (len == 4) /*about to get too large*/
00784             goto error;
00785         
00786         if (ch == chendscanstring) /*test before doing esc sequences*/
00787             goto error;
00788         
00789         if (ch == '\\')
00790             ch = parsepopescapesequence ();
00791         
00792         ch4 [len++] = ch; /*add character to constant*/
00793         } /*while*/
00794     
00795     error:
00796     
00797     ctscanlines = lnum; /*make error message point at string start*/
00798     
00799     ctscanchars = cnum;
00800     
00801     langerror (badcharconsterror);
00802     
00803     return (false);
00804     } /*parsepopcharconst*/
00805     
00806 
00807 static tokentype langscanner (hdltreenode *nodetoken) {
00808     
00809     /*
00810     scan the input string for the next token, return the character 
00811     that we stopped on in chtoken.
00812     
00813     if it's an identifier or a constant, nodetoken will be non-nil.
00814     
00815     11/22/91 dmb: return zero when out of text, after returning exactly 
00816     one (non-zero) eoltoken.
00817     
00818     5.0.2b10 dmb: exempt const identifier from tmp stack before pushing it
00819     into code tree. it will be disposed on error
00820     */
00821     
00822     register byte ch, chfirst, chsecond;
00823     bigstring bs;
00824     tyvaluerecord val;
00825     hdlhashnode hnode;
00826     
00827     *nodetoken = nil; /*default*/
00828     
00829     #ifdef fldebug
00830     
00831     setstringlength (bstoken, 0); 
00832     
00833     #endif
00834     
00835     if (!parsepopblanks ()) { /*ran out of text*/
00836         
00837         if (flsenteol)
00838             return (0);
00839         
00840         flsenteol = true; /*we're about to...*/
00841         
00842         return (eoltoken);
00843         }
00844     
00845     chfirst = ch = parsefirstchar (); /*lookahead at the next character*/
00846     
00847     if (ch == chsinglequote) { /*a single-quote, character constant*/
00848         
00849         if (!parsepopcharconst (&val))
00850             return (errortoken);
00851         
00852         if (!newconstnode (val, nodetoken))
00853             return (0 /*errortoken*/);
00854             
00855         return (constanttoken);
00856         }
00857     
00858     if ((ch == chdoublequote) || (ch == chopencurlyquote)) { /*a string constant*/
00859         
00860         initvalue (&val, stringvaluetype);
00861         
00862         if (!parsepopstringconst (&val.data.stringvalue))
00863             return (errortoken);
00864         
00865         #ifdef fldebug
00866         
00867         texthandletostring (val.data.stringvalue, bstoken); /*8/13*/
00868         
00869         #endif
00870         
00871         if (!newconstnode (val, nodetoken))
00872             return (0 /*errortoken*/);
00873         
00874         return (constanttoken);
00875         }
00876     
00877     if (isdigit (ch)) {
00878         
00879         if (!parsepopnumber (&val)) /*might be a long or a float*/
00880             return (errortoken);
00881         
00882         if (!newconstnode (val, nodetoken))
00883             return (0 /*errortoken*/);
00884         
00885         return (constanttoken);
00886         }
00887     
00888     if (isfirstidentifierchar (ch)) {
00889         
00890         register boolean fl;
00891         
00892         parsepopidentifier (bs);
00893         
00894         #ifdef fldebug
00895         
00896         copystring (bs, bstoken);
00897         
00898         #endif
00899         
00900         fl = hashtablelookup (hkeywordtable, bs, &val, &hnode);
00901         
00902         if (fl) 
00903             return ((tokentype) val.data.tokenvalue); /*it's a reserved word*/
00904         
00905         fl = hashtablelookup (hconsttable, bs, &val, &hnode);
00906         
00907         if (fl) { /*it's a pre-defined constant*/
00908             
00909             if (!copyvaluerecord (val, &val))
00910                 return (0);
00911             
00912             exemptfromtmpstack (&val);
00913             
00914             if (!newconstnode (val, nodetoken))
00915                 return (0 /*errortoken*/);
00916             
00917             return (constanttoken);
00918             }
00919         
00920         initvalue (&val, stringvaluetype);
00921         
00922         if (!newtexthandle (bs, &val.data.stringvalue))
00923             return (0 /*errortoken*/);
00924         
00925         if (!newidnode (val, nodetoken))
00926             return (0 /*errortoken*/);
00927         
00928         return (identifiertoken);
00929         }
00930     
00931     parsepopchar (); /*consume the token char*/
00932     
00933     chsecond = parsefirstchar (); /*may need to look ahead to determine this token*/
00934     
00935     #ifdef fldebug
00936     
00937     pushchar (chfirst, bstoken);
00938     
00939     #endif
00940     
00941     switch (chfirst) {
00942         
00943         case ',': case '(': case ')': case ';': case '{': case '}': case '.':
00944         
00945         case ':':
00946         
00947         case '[': case ']': case '@': case '^':
00948             return (chfirst); /*the ascii value is the token*/
00949         
00950         case (byte) '¥':
00951             return ('.');
00952         
00953         case chnotequals:
00954             return (NEtoken);
00955             
00956         case '*':
00957             return (multiplytoken);
00958         
00959         case '/': case chdivide:
00960             return (dividetoken);
00961         
00962         case '%':
00963             return (modtoken);
00964         
00965         case (byte) '²':
00966             return (LEtoken);
00967             
00968         case (byte) '³':
00969             return (GEtoken);
00970             
00971         case '+':
00972             if (chsecond == '+') {
00973                 
00974                 parsepopchar (); /*consume the second char*/
00975                 
00976                 #ifdef fldebug
00977                 
00978                 pushchar ('+', bstoken);
00979                 
00980                 #endif
00981                 
00982                 return (plusplustoken);
00983                 }
00984                 
00985             return (addtoken);
00986             
00987         case '-':
00988             if (chsecond == '-') {
00989                 
00990                 #ifdef fldebug
00991                 
00992                 pushchar ('-', bstoken);
00993                 
00994                 #endif
00995                 
00996                 parsepopchar (); /*consume the second char*/
00997                 
00998                 return (minusminustoken);
00999                 }
01000                 
01001             return (subtracttoken);
01002             
01003         case '=':
01004             if (chsecond == '=') {
01005                 
01006                 parsepopchar (); /*consume the second char*/
01007                 
01008                 #ifdef fldebug
01009                 
01010                 pushchar ('=', bstoken);
01011                 
01012                 #endif
01013                 
01014                 return (EQtoken);
01015                 }
01016                 
01017             return (assigntoken);
01018             
01019         case '&':
01020             if (chsecond == '&') {
01021                 
01022                 parsepopchar (); /*consume the second char*/
01023                 
01024                 #ifdef fldebug
01025                 
01026                 pushchar ('&', bstoken);
01027                 
01028                 #endif
01029                 
01030                 return (andandtoken);
01031                 }
01032                 
01033             return (bitandtoken);
01034             
01035         case '|':
01036             if (chsecond == '|') {
01037                 
01038                 parsepopchar (); /*consume the second char*/
01039                 
01040                 #ifdef fldebug
01041                 
01042                 pushchar ('|', bstoken);
01043                 
01044                 #endif
01045                 
01046                 return (orortoken);
01047                 }
01048                 
01049             return (bitortoken);
01050             
01051         case '<':
01052             if (chsecond == '=') {
01053                 
01054                 parsepopchar (); /*consume the second char*/
01055                 
01056                 #ifdef fldebug
01057                 
01058                 pushchar ('=', bstoken);
01059                 
01060                 #endif
01061                 
01062                 return (LEtoken);
01063                 }
01064                 
01065             return (LTtoken);
01066             
01067         case '>':
01068             if (chsecond == '=') {
01069                 
01070                 parsepopchar (); /*consume the second char*/
01071                 
01072                 #ifdef fldebug
01073                 
01074                 pushchar ('=', bstoken);
01075                 
01076                 #endif
01077                 
01078                 return (GEtoken);
01079                 }
01080                 
01081             return (GTtoken);
01082             
01083         case '!':
01084             if (chsecond == '=') {
01085                 
01086                 parsepopchar (); /*consume the second char*/
01087                 
01088                 #ifdef fldebug
01089                 
01090                 pushchar ('=', bstoken);
01091                 
01092                 #endif
01093                 
01094                 return (NEtoken);
01095                 }
01096                 
01097             return (nottoken);
01098         } /*switch*/
01099     
01100     setstringwithchar (chfirst, bstoken);
01101     
01102     //assert (ixparsestring <= lenparsestring && hscanstring);
01103     
01104     langparamerror (illegaltokenerror, bstoken); /*all the legal tokens are caught above*/
01105     
01106     return (errortoken);
01107     } /*langscanner*/
01108 
01109 
01110 tokentype parsegettoken (hdltreenode *nodetoken) {
01111     
01112     /*
01113     a bottleneck that makes debugging easier.  
01114     
01115     if you want to see the string that generated the current token, 
01116     display "bstoken" -- its a globalÉ
01117     */
01118     
01119     register tokentype token;
01120     
01121     token = langscanner (nodetoken);
01122     
01123     return (token);
01124     } /*parsegettoken*/
01125 
01126 
01127 boolean langstriptextsyntax (Handle htext) {
01128     
01129     /*
01130     strip out braces and semicolons from the source text, so it 
01131     can be pasted into a script outline
01132     */
01133     
01134     boolean fldone = false;
01135     hdltreenode hnode;
01136     tokentype token, token2 = 0;
01137     long ixstart;
01138     long ix1 = 0, ix2 = 0;
01139     unsigned long line2 =  0;
01140     short ctendbraces = 0;
01141     
01142     parsesetscanstring (htext, true);
01143     
01144     disablelangerror ();
01145     
01146     while (!fldone) {
01147         
01148         ixstart = ixparsestring;
01149         
01150         token = langscanner (&hnode);
01151         
01152         langdisposetree (hnode); /*we don't need it*/
01153         
01154         if (ix2 > 0) { /*something waiting to be stripped*/
01155             
01156             if ((token2 == '}') && (ctendbraces > 0))
01157                 --ctendbraces;
01158             
01159             else {
01160                 
01161                 if ((token2 == '}') || (ctscanlines > line2)) { /*we got a return, go ahead & strip it*/
01162                     
01163                     short len;
01164                     
01165                     if (token2 == '}') /* 2005-01-15 creedon - fix suggested by JES w/caveats < http://sourceforge.net/tracker/index.php?func=detail&aid=1093595&group_id=120666&atid=687798 > */
01166                         ix1 = ix2 - 1;
01167 
01168                     len = ix2 - ix1;
01169                     
01170                     pullfromhandle (htext, ix1, len, nil); /*get rid of the token source*/
01171                     
01172                     lenparsestring -= len; /*make adjustments*/
01173                     
01174                     ixparsestring -= len; /*ditto*/
01175                     
01176                     ixstart -= len;
01177                     
01178                     ctendbraces = 0; /*reset*/
01179                     }
01180                 else {
01181                     
01182                     if (token2 == '{')
01183                         ++ctendbraces;
01184                     }
01185                 }
01186             
01187             ix2 = 0; /*reset*/
01188             }
01189         
01190         switch (token) {
01191             
01192             case errortoken:
01193             case eoltoken:
01194                 fldone = true;
01195                 
01196                 break;
01197             
01198             case '{':
01199             case '}':
01200             case ';':
01201                 token2 = token;
01202                 
01203                 ix1 = ixstart;
01204                 
01205                 ix2 = ixparsestring;
01206                 
01207                 line2 = ctscanlines;
01208                 
01209                 break;
01210             
01211             default:
01212                 break;
01213             }
01214         }
01215     
01216     if (ix2 > 0) /*something waiting to be stripped*/
01217         pullfromhandle (htext, ix1, ix2 - ix1, nil);
01218     
01219     enablelangerror ();
01220     
01221     return (true);
01222     } /*langstriptextsyntax*/
01223 
01224 
01225 boolean langaddapplescriptsyntax (Handle hscript) {
01226     
01227     /*
01228     add vertical bars where necessary to "quote" UserTalk dotted 
01229     identifiers for AppleScript.
01230     */
01231     
01232     boolean fldone = false;
01233     hdltreenode hnode;
01234     tokentype token, lasttoken = 0;
01235     long ixstart;
01236     long ix1 = 0;
01237     unsigned long line1 = 0;
01238     bigstring bsid;
01239     boolean flgotid = false;
01240     boolean flgotdottedid = false;
01241     byte chbar = '|';
01242     
01243     parsesetscanstring (hscript, true);
01244     
01245     disablelangerror ();
01246     
01247     while (!fldone) {
01248         
01249         ixstart = ixparsestring;
01250         
01251         token = langscanner (&hnode);
01252         
01253         switch (token) {
01254             
01255             /*
01256             case errortoken:
01257                 flgotbar == firstchar (bstoken) == (byte) '|';
01258                 
01259                 flgotid = false;
01260                 
01261                 break;
01262             */
01263             
01264             case eoltoken:
01265                 fldone = true;
01266                 
01267                 break;
01268             
01269             case identifiertoken:
01270                 if (flgotid && lasttoken == '.') { /*continuation of a dotted id*/
01271                     
01272                     flgotdottedid = true;
01273                     }
01274                 else { /*treat as beginning of a new id*/
01275                     
01276                     flgotid = true;
01277                     
01278                     flgotdottedid = false;
01279                     
01280                     pullstringvalue (&(**hnode).nodeval, bsid);
01281                     
01282                     ix1 = ixparsestring - stringlength (bsid);
01283                     
01284                     line1 = ctscanlines;
01285                     }
01286                 
01287                 break;
01288             
01289             case '.':
01290                 if (lasttoken == identifiertoken) /*don't have dottedid, until we get another identifier*/
01291                     flgotdottedid = false;
01292                 else
01293                     flgotid = false;
01294                 
01295                 break;
01296             
01297             case '(':
01298                 if (flgotid && flgotdottedid && ctscanlines == line1) { /*we're there*/
01299                     
01300                     insertinhandle (hscript, ixstart, &chbar, sizeof (chbar)); /*do second bar 1st*/
01301                     
01302                     insertinhandle (hscript, ix1, &chbar, sizeof (chbar));
01303                     
01304                     lenparsestring += 2; /*make adjustments*/
01305                     
01306                     ixparsestring += 2; /*ditto*/
01307                     }
01308                 
01309                 flgotid = false;
01310                 
01311                 break;
01312             
01313             default:
01314                 /*
01315                 flgotbar = false;
01316                 */
01317                 
01318                 flgotid = false;
01319                 
01320                 break;
01321             }
01322         
01323         langdisposetree (hnode); /*we don't need it anymore*/
01324         
01325         lasttoken = token;
01326         }
01327     
01328     enablelangerror ();
01329     
01330     return (true);
01331     } /*langaddapplescriptsyntax*/
01332 
01333 
01334 
01335 /*
01336 yyoverflow (bsevent, p1, size1, p2, size2, p3, size3, p4) bigstring bsevent; ptrbyte p1, p2, p3; short size1, size2, size3; {
01337     
01338     DebugStr ("\pyyoverflow");
01339     } /%yyoverflow%/
01340 */
01341 
01342 #endif
01343 
01344 
01345 
01346 
01347 
01348     
01349     
01350     
01351 

Generated on Wed May 31 18:19:53 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6