home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Programming / ICU / src / icu / source / tools / genrb / parse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-19  |  10.7 KB  |  369 lines

  1. /*
  2. *******************************************************************************
  3. *                                                                             *
  4. * COPYRIGHT:                                                                  *
  5. *   (C) Copyright International Business Machines Corporation, 1998, 1999     *
  6. *   Licensed Material - Program-Property of IBM - All Rights Reserved.        *
  7. *   US Government Users Restricted Rights - Use, duplication, or disclosure   *
  8. *   restricted by GSA ADP Schedule Contract with IBM Corp.                    *
  9. *                                                                             *
  10. *******************************************************************************
  11. *
  12. * File parse.c
  13. *
  14. * Modification History:
  15. *
  16. *   Date        Name        Description
  17. *   05/26/99    stephen     Creation.
  18. *******************************************************************************
  19. */
  20.  
  21. #include "parse.h"
  22. #include "error.h"
  23. #include "uhash.h"
  24. #include "cmemory.h"
  25. #include "read.h"
  26. #include "ufile.h"
  27. #include "ustdio.h"
  28. #include "ustr.h"
  29. #include "list.h"
  30. #include "rblist.h"
  31. #include "ustring.h"
  32.  
  33. /* Node IDs for the state transition table. */
  34. enum ENode {
  35.   eError,
  36.   eInitial,   /* Next: Locale name */
  37.   eGotLoc,    /* Next: { */
  38.   eIdle,      /* Next: Tag name | } */
  39.   eGotTag,    /* Next: { */
  40.   eNode5,     /* Next: Data | Subtag */
  41.   eNode6,     /* Next: } | { | , */
  42.   eList,      /* Next: List data */
  43.   eNode8,     /* Next: , */
  44.   eTagList,   /* Next: Subtag data */
  45.   eNode10,    /* Next: } */
  46.   eNode11,    /* Next: Subtag */
  47.   eNode12,    /* Next: { */
  48.   e2dArray,   /* Next: Data | } */
  49.   eNode14,    /* Next: , | } */
  50.   eNode15,    /* Next: , | } */
  51.   eNode16     /* Next: { | } */
  52. };
  53.  
  54. /* Action codes for the state transtiion table. */
  55. enum EAction {
  56.   /* Generic actions */
  57.   eNOP       = 0x0100, /* Do nothing */
  58.   eOpen      = 0x0200, /* Open a new locale data block with the data
  59.               string as the locale name */
  60.   eClose     = 0x0300, /* Close a locale data block */
  61.   eSetTag    = 0x0400, /* Record the last string as the tag name */
  62.   
  63.   /* Comma-delimited lists */
  64.   eBegList   = 0x1100, /* Start a new string list with the last string
  65.               as the first element */
  66.   eEndList   = 0x1200, /* Close a string list being built */
  67.   eListStr   = 0x1300, /* Record the last string as a data string and
  68.               increment the index */
  69.   eStr       = 0x1400, /* Record the last string as a singleton string */
  70.   
  71.   /* 2-d lists */
  72.   eBeg2dList = 0x2100, /* Start a new 2d string list with no elements as yet */
  73.   eEnd2dList = 0x2200, /* Close a 2d string list being built */
  74.   e2dStr     = 0x2300, /* Record the last string as a 2d string */
  75.   eNewRow    = 0x2400, /* Start a new row */
  76.   
  77.   /* Tagged lists */
  78.   eBegTagged = 0x3100, /* Start a new tagged list with the last
  79.               string as the first subtag */
  80.   eEndTagged = 0x3200, /* Close a tagged list being build */
  81.   eSubtag    = 0x3300, /* Record the last string as the subtag */
  82.   eTaggedStr = 0x3400  /* Record the last string as a tagged string */
  83. };
  84.  
  85. /* A struct which encapsulates a node ID and an action. */
  86. struct STransition {
  87.   enum ENode fNext;
  88.   enum EAction fAction;
  89. };
  90.  
  91. /* This table describes an ATM (state machine) which parses resource
  92.    bundle text files rather strictly. Each row represents a node. The
  93.    columns of that row represent transitions into other nodes. Most
  94.    transitions are "eError" because most transitions are
  95.    disallowed. For example, if the parser has just seen a tag name, it
  96.    enters node 4 ("eGotTag"). The state table then marks only one
  97.    valid transition, which is into node 5, upon seeing an eOpenBrace
  98.    token. We allow an extra comma after the last element in a
  99.    comma-delimited list (transition from eList to eIdle on
  100.    kCloseBrace). */
  101. static struct STransition gTransitionTable [] = {
  102.   /* kString           kOpenBrace            kCloseBrace         kComma*/
  103.   {eError,eNOP},       {eError,eNOP},        {eError,eNOP},      {eError,eNOP},
  104.   
  105.   {eGotLoc,eOpen},     {eError,eNOP},        {eError,eNOP},      {eError,eNOP},
  106.   {eError,eNOP},       {eIdle,eNOP},         {eError,eNOP},      {eError,eNOP},
  107.   
  108.   {eGotTag,eSetTag},   {eError,eNOP},        {eInitial,eClose},  {eError,eNOP},
  109.   {eError,eNOP},       {eNode5,eNOP},        {eError,eNOP},      {eError,eNOP},
  110.   {eNode6,eNOP},       {e2dArray,eBeg2dList},{eError,eNOP},      {eError,eNOP},
  111.   {eError,eNOP},       {eTagList,eBegTagged},{eIdle,eStr},       {eList,eBegList},
  112.   
  113.   {eNode8,eListStr},   {eError,eNOP},         {eIdle,eEndList},  {eError,eNOP},
  114.   {eError,eNOP},       {eError,eNOP},         {eIdle,eEndList},  {eList,eNOP},
  115.   
  116.   {eNode10,eTaggedStr},{eError,eNOP},         {eError,eNOP},     {eError,eNOP},
  117.   {eError,eNOP},       {eError,eNOP},         {eNode11,eNOP},    {eError,eNOP},
  118.   {eNode12,eNOP},      {eError,eNOP},         {eIdle,eEndTagged},{eError,eNOP},
  119.   {eError,eNOP},       {eTagList,eSubtag},    {eError,eNOP},     {eError,eNOP},
  120.  
  121.   {eNode14,e2dStr},    {eError,eNOP},         {eNode15,eNOP},    {eError,eNOP},
  122.   {eError,eNOP},       {eError,eNOP},         {eNode15,eNOP},    {e2dArray,eNOP},
  123.   {eError,eNOP},       {e2dArray,eNewRow},    {eIdle,eEnd2dList},{eNode16,eNOP},
  124.   {eError,eNOP},       {e2dArray,eNewRow},    {eIdle,eEnd2dList},{eError,eNOP} 
  125. };
  126.  
  127. /* Row length is 4 */
  128. #define GETTRANSITION(row,col) (gTransitionTable[col + (row<<2)])
  129.  
  130. struct SRBItemList*
  131. parse(FileStream *f,
  132.       UErrorCode *status)
  133. {
  134.   struct UFILE *file;
  135.   enum ETokenType type;
  136.   enum ENode node;
  137.   struct STransition t;
  138.  
  139.   struct UString token;
  140.   struct UString tag;
  141.   struct UString subtag;
  142.   struct UString localeName;
  143.   struct UString keyname;
  144.  
  145.   struct SRBItem *item;
  146.   struct SRBItemList *list;
  147.   struct SList *current;
  148.  
  149.   /* Hashtable for keeping track of seen tag names */
  150.   struct UHashtable *data;
  151.  
  152.  
  153.   if(U_FAILURE(*status)) return 0;
  154.  
  155.   /* setup */
  156.  
  157.   ustr_init(&token);
  158.   ustr_init(&tag);
  159.   ustr_init(&subtag);
  160.   ustr_init(&localeName);
  161.   ustr_init(&keyname);
  162.  
  163.   node = eInitial;
  164.   data = 0;
  165.   current = 0;
  166.   item = 0;
  167.  
  168.   file = u_finit(f, status);
  169.   list = rblist_open(status);
  170.   if(U_FAILURE(*status)) goto finish;
  171.   
  172.   /* iterate through the stream */
  173.   for(;;) {
  174.  
  175.     /* get next token from stream */
  176.     type = getNextToken(file, &token, status);
  177.     if(U_FAILURE(*status)) goto finish;
  178.  
  179.     switch(type) {
  180.     case tok_EOF:
  181.       *status = (node == eInitial) ? U_ZERO_ERROR : U_INVALID_FORMAT_ERROR;
  182.       setErrorText("Unexpected EOF encountered");
  183.       goto finish;
  184.       /*break;*/
  185.  
  186.     case tok_error:
  187.       *status = U_INVALID_FORMAT_ERROR;
  188.       goto finish;
  189.       /*break;*/
  190.       
  191.     default:
  192.       break;
  193.     }
  194.     
  195.     t = GETTRANSITION(node, type);
  196.     node = t.fNext;
  197.     
  198.     if(node == eError) {
  199.       *status = U_INVALID_FORMAT_ERROR;
  200.       goto finish;
  201.     }
  202.     
  203.     switch(t.fAction) {
  204.     case eNOP:
  205.       break;
  206.       
  207.       /* Record the last string as the tag name */
  208.     case eSetTag:
  209.       ustr_cpy(&tag, &token, status);
  210.       if(U_FAILURE(*status)) goto finish;
  211.       if(uhash_get(data, uhash_hashUString(tag.fChars)) != 0) {
  212.      char *s;
  213.     *status = U_INVALID_FORMAT_ERROR;
  214.        s = icu_malloc(1024);
  215.        strcpy(s, "Duplicate tag name detected: ");
  216.        u_austrcpy(s+strlen(s), tag.fChars);
  217.        setErrorText(s);
  218.     goto finish;
  219.       }
  220.       break;
  221.  
  222.       /* Record a singleton string */
  223.     case eStr:
  224.       if(current != 0) {
  225.     *status = U_INTERNAL_PROGRAM_ERROR;
  226.     goto finish;
  227.       }
  228.       current = strlist_open(status);
  229.       strlist_add(current, token.fChars, status);
  230.       item = make_rbitem(tag.fChars, current, status);
  231.       rblist_add(list, item, status);
  232.       uhash_put(data, tag.fChars, status);
  233.       if(U_FAILURE(*status)) goto finish;
  234.       current = 0;
  235.       item = 0;
  236.       break;
  237.  
  238.       /* Begin a string list */
  239.     case eBegList:
  240.       if(current != 0) {
  241.     *status = U_INTERNAL_PROGRAM_ERROR;
  242.     goto finish;
  243.       }
  244.       current = strlist_open(status);
  245.       strlist_add(current, token.fChars, status);
  246.       if(U_FAILURE(*status)) goto finish;
  247.       break;
  248.       
  249.       /* Record a comma-delimited list string */      
  250.     case eListStr:
  251.       strlist_add(current, token.fChars, status);
  252.       if(U_FAILURE(*status)) goto finish;
  253.       break;
  254.       
  255.       /* End a string list */
  256.     case eEndList:
  257.       uhash_put(data, tag.fChars, status);
  258.       item = make_rbitem(tag.fChars, current, status);
  259.       rblist_add(list, item, status);
  260.       if(U_FAILURE(*status)) goto finish;
  261.       current = 0;
  262.       item = 0;
  263.       break;
  264.       
  265.     case eBeg2dList:
  266.       if(current != 0) {
  267.     *status = U_INTERNAL_PROGRAM_ERROR;
  268.     goto finish;
  269.       }
  270.       current = strlist2d_open(status);
  271.       if(U_FAILURE(*status)) goto finish;
  272.       break;
  273.       
  274.     case eEnd2dList:
  275.       uhash_put(data, tag.fChars, status);
  276.       item = make_rbitem(tag.fChars, current, status);
  277.       rblist_add(list, item, status);
  278.       if(U_FAILURE(*status)) goto finish;
  279.       current = 0;
  280.       item = 0;
  281.       break;
  282.       
  283.     case e2dStr:
  284.       strlist2d_add(current, token.fChars, status);
  285.       if(U_FAILURE(*status)) goto finish;
  286.       break;
  287.       
  288.     case eNewRow:
  289.       strlist2d_newRow(current, status);
  290.       if(U_FAILURE(*status)) goto finish;
  291.       break;
  292.       
  293.     case eBegTagged:
  294.       if(current != 0) {
  295.     *status = U_INTERNAL_PROGRAM_ERROR;
  296.     goto finish;
  297.       }
  298.       current = taglist_open(status);
  299.       ustr_cpy(&subtag, &token, status);
  300.       if(U_FAILURE(*status)) goto finish;
  301.       break;
  302.       
  303.     case eEndTagged:
  304.       uhash_put(data, tag.fChars, status);
  305.       item = make_rbitem(tag.fChars, current, status);
  306.       rblist_add(list, item, status);
  307.       if(U_FAILURE(*status)) goto finish;
  308.       current = 0;
  309.       item = 0;
  310.       break;
  311.       
  312.     case eTaggedStr:
  313.       taglist_add(current, subtag.fChars, token.fChars, status);
  314.       if(U_FAILURE(*status)) goto finish;
  315.       break;
  316.       
  317.       /* Record the last string as the subtag */
  318.     case eSubtag:
  319.       ustr_cpy(&subtag, &token, status);
  320.       if(U_FAILURE(*status)) goto finish;
  321.       if(taglist_get(current, subtag.fChars, status) != 0) {
  322.     *status = U_INVALID_FORMAT_ERROR;
  323.     setErrorText("Duplicate subtag found in tagged list");
  324.     goto finish;
  325.       }
  326.       break;
  327.       
  328.     case eOpen:
  329.       if(data != 0) {
  330.     *status = U_INTERNAL_PROGRAM_ERROR;
  331.     goto finish;
  332.       }
  333.       ustr_cpy(&localeName, &token, status);
  334.       rblist_setlocale(list, localeName.fChars, status);
  335.       if(U_FAILURE(*status)) goto finish;
  336.       data = uhash_open(uhash_hashUString, status);
  337.       break;
  338.       
  339.     case eClose:
  340.       if(data == 0) {
  341.     *status = U_INTERNAL_PROGRAM_ERROR;
  342.     goto finish;
  343.       }
  344.       break;
  345.     }
  346.   }
  347.  
  348.  finish:
  349.  
  350.   /* clean  up */
  351.   
  352.   if(data != 0)
  353.     uhash_close(data);
  354.  
  355.   if(item != 0)
  356.     icu_free(item);
  357.  
  358.   ustr_deinit(&token);
  359.   ustr_deinit(&tag);
  360.   ustr_deinit(&subtag);
  361.   ustr_deinit(&localeName);
  362.   ustr_deinit(&keyname);
  363.  
  364.   if(file != 0)
  365.     u_fclose(file);
  366.  
  367.   return list;
  368. }
  369.