diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2008-08-19 23:16:45 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2008-08-19 23:16:45 +0000 |
commit | 105215cc7a1ee50bdced4a0e64ec5efd84ae6377 (patch) | |
tree | f66a373f7d62b27f1322ecd26b675c5a8e54a178 /nuttx | |
parent | 2cde9d488e766651e1641d9ab4c41237c3647fa3 (diff) | |
download | px4-nuttx-105215cc7a1ee50bdced4a0e64ec5efd84ae6377.tar.gz px4-nuttx-105215cc7a1ee50bdced4a0e64ec5efd84ae6377.tar.bz2 px4-nuttx-105215cc7a1ee50bdced4a0e64ec5efd84ae6377.zip |
Support nested if-then[-else]-fi
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@832 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx')
-rw-r--r-- | nuttx/examples/README.txt | 4 | ||||
-rw-r--r-- | nuttx/examples/nsh/nsh.h | 27 | ||||
-rw-r--r-- | nuttx/examples/nsh/nsh_main.c | 117 |
3 files changed, 109 insertions, 39 deletions
diff --git a/nuttx/examples/README.txt b/nuttx/examples/README.txt index a3cf60a45..130ab5cb5 100644 --- a/nuttx/examples/README.txt +++ b/nuttx/examples/README.txt @@ -79,6 +79,10 @@ examples/nsh new threads are generated when a command is executed in background or as new TELNET connections are established. + * CONFIG_EXAMPLES_NSH_NESTDEPTH + The maximum number of nested if-then[-else]-fi sequences that + are permissable. Default: 3 + * CONFIG_EXAMPLES_NSH_CONSOLE If CONFIG_EXAMPLES_NSH_CONSOLE is set to 'y', then a serial console front-end is selected. diff --git a/nuttx/examples/nsh/nsh.h b/nuttx/examples/nsh/nsh.h index 574e03221..57c75e1bc 100644 --- a/nuttx/examples/nsh/nsh.h +++ b/nuttx/examples/nsh/nsh.h @@ -87,6 +87,14 @@ # define CONFIG_EXAMPLES_NSH_STACKSIZE 4096 #endif +/* The maximum number of nested if-then[-else]-fi sequences that + * are permissable. + */ + +#ifndef CONFIG_EXAMPLES_NSH_NESTDEPTH +# define CONFIG_EXAMPLES_NSH_NESTDEPTH 3 +#endif + /* Define to enable dumping of all input/output buffers */ #undef CONFIG_EXAMPLES_NSH_TELNETD_DUMPBUFFER @@ -120,14 +128,27 @@ enum nsh_parser_e NSH_PARSER_ELSE }; +struct nsh_state_s +{ + ubyte ns_ifcond : 1; /* Value of command in 'if' statement */ + ubyte ns_disabled : 1; /* TRUE: Unconditionally disabled */ + ubyte ns_unused : 4; + ubyte ns_state : 2; /* Parser state (see enum nsh_parser_e) */ +}; + struct nsh_parser_s { boolean np_bg; /* TRUE: The last command executed in background */ boolean np_redirect; /* TRUE: Output from the last command was re-directed */ boolean np_fail; /* TRUE: The last command failed */ - boolean np_ifcond; /* Value of command in 'if' statement */ - ubyte np_state; /* Parser state (see enum nsh_parser_e) */ + ubyte np_ndx; /* Current index into np_st[] */ int np_nice; /* "nice" value applied to last background cmd */ + + /* This is a stack of parser state information. It supports nested + * execution of commands that span multiple lines (like if-then-else-fi) + */ + + struct nsh_state_s np_st[CONFIG_EXAMPLES_NSH_NESTDEPTH]; }; struct nsh_vtbl_s @@ -165,9 +186,11 @@ extern const char g_fmtcmdnotfound[]; extern const char g_fmtcmdnotimpl[]; extern const char g_fmtnosuch[]; extern const char g_fmttoomanyargs[]; +extern const char g_fmtdeepnesting[]; extern const char g_fmtcontext[]; extern const char g_fmtcmdfailed[]; extern const char g_fmtcmdoutofmemory[]; +extern const char g_fmtinternalerror[]; /**************************************************************************** * Public Function Prototypes diff --git a/nuttx/examples/nsh/nsh_main.c b/nuttx/examples/nsh/nsh_main.c index 8c2999cf7..ff3398ea1 100644 --- a/nuttx/examples/nsh/nsh_main.c +++ b/nuttx/examples/nsh/nsh_main.c @@ -156,6 +156,7 @@ const char g_fmtcmdnotfound[] = "nsh: %s: command not found\n"; const char g_fmtcmdnotimpl[] = "nsh: %s: command not implemented\n"; const char g_fmtnosuch[] = "nsh: %s: no such %s: %s\n"; const char g_fmttoomanyargs[] = "nsh: %s: too many arguments\n"; +const char g_fmtdeepnesting[] = "nsh: %s: nesting too deep\n"; const char g_fmtcontext[] = "nsh: %s: not valid in this context\n"; #ifdef CONFIG_EXAMPLES_NSH_STRERROR const char g_fmtcmdfailed[] = "nsh: %s: %s failed: %s\n"; @@ -163,6 +164,7 @@ const char g_fmtcmdfailed[] = "nsh: %s: %s failed: %s\n"; const char g_fmtcmdfailed[] = "nsh: %s: %s failed: %d\n"; #endif const char g_fmtcmdoutofmemory[] = "nsh: %s: out of memory\n"; +const char g_fmtinternalerror[] = "nsh: %s: Internal error\n"; /**************************************************************************** * Private Functions @@ -434,12 +436,44 @@ char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, char **saveptr) } /**************************************************************************** + * Name: nsh_cmdenabled + ****************************************************************************/ + +static inline boolean nsh_cmdenabled(FAR struct nsh_vtbl_s *vtbl) +{ + struct nsh_parser_s *np = &vtbl->np; + boolean ret = !np->np_st[np->np_ndx].ns_disabled; + if (ret) + { + switch (np->np_st[np->np_ndx].ns_state) + { + case NSH_PARSER_NORMAL : + case NSH_PARSER_IF: + default: + break; + + case NSH_PARSER_THEN: + ret = !np->np_st[np->np_ndx].ns_ifcond; + break; + + case NSH_PARSER_ELSE: + ret = np->np_st[np->np_ndx].ns_ifcond; + break; + } + } + return ret; +} + +/**************************************************************************** * Name: nsh_ifthenelse ****************************************************************************/ static inline int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, FAR char **saveptr) { + struct nsh_parser_s *np = &vtbl->np; FAR char *cmd = *ppcmd; + boolean disabled; + if (cmd) { /* Check if the command is preceeded by "if" */ @@ -457,12 +491,29 @@ static inline int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, /* Verify that "if" is valid in this context */ - if (vtbl->np.np_state != NSH_PARSER_NORMAL) + if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_NORMAL && + np->np_st[np->np_ndx].ns_state != NSH_PARSER_THEN && + np->np_st[np->np_ndx].ns_state != NSH_PARSER_ELSE) { nsh_output(vtbl, g_fmtcontext, "if"); goto errout; } - vtbl->np.np_state = NSH_PARSER_IF; + + /* Check if we have exceeded the maximum depth of nesting */ + + if (np->np_ndx >= CONFIG_EXAMPLES_NSH_NESTDEPTH-1) + { + nsh_output(vtbl, g_fmtdeepnesting, "if"); + goto errout; + } + + /* "Push" the old state and set the new state */ + + disabled = !nsh_cmdenabled(vtbl); + np->np_ndx++; + np->np_st[np->np_ndx].ns_state = NSH_PARSER_IF; + np->np_st[np->np_ndx].ns_disabled = disabled; + np->np_st[np->np_ndx].ns_ifcond = FALSE; } else if (strcmp(cmd, "then") == 0) { @@ -477,12 +528,12 @@ static inline int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, /* Verify that "then" is valid in this context */ - if (vtbl->np.np_state != NSH_PARSER_IF) + if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_IF) { nsh_output(vtbl, g_fmtcontext, "then"); goto errout; } - vtbl->np.np_state = NSH_PARSER_THEN; + np->np_st[np->np_ndx].ns_state = NSH_PARSER_THEN; } else if (strcmp(cmd, "else") == 0) { @@ -497,12 +548,12 @@ static inline int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, /* Verify that "then" is valid in this context */ - if (vtbl->np.np_state != NSH_PARSER_THEN) + if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_THEN) { nsh_output(vtbl, g_fmtcontext, "else"); goto errout; } - vtbl->np.np_state = NSH_PARSER_ELSE; + np->np_st[np->np_ndx].ns_state = NSH_PARSER_ELSE; } else if (strcmp(cmd, "fi") == 0) { @@ -517,14 +568,24 @@ static inline int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, /* Verify that "fi" is valid in this context */ - if (vtbl->np.np_state != NSH_PARSER_THEN && vtbl->np.np_state != NSH_PARSER_ELSE) + if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_THEN && + np->np_st[np->np_ndx].ns_state != NSH_PARSER_ELSE) { nsh_output(vtbl, g_fmtcontext, "fi"); goto errout; } - vtbl->np.np_state = NSH_PARSER_NORMAL; + + if (np->np_ndx < 1) /* Shouldn't happen */ + { + nsh_output(vtbl, g_fmtinternalerror, "if"); + goto errout; + } + + /* "Pop" the previous state */ + + np->np_ndx--; } - else if (vtbl->np.np_state == NSH_PARSER_IF) + else if (np->np_st[np->np_ndx].ns_state == NSH_PARSER_IF) { nsh_output(vtbl, g_fmtcontext, cmd); goto errout; @@ -533,48 +594,30 @@ static inline int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, return OK; errout: - vtbl->np.np_state = NSH_PARSER_NORMAL; + np->np_ndx = 0; + np->np_st[0].ns_state = NSH_PARSER_NORMAL; + np->np_st[0].ns_disabled = FALSE; + np->np_st[0].ns_ifcond = FALSE; return ERROR; } /**************************************************************************** - * Name: nsh_cmdenabled - ****************************************************************************/ - -static inline boolean nsh_cmdenabled(FAR struct nsh_vtbl_s *vtbl) -{ - switch (vtbl->np.np_state) - { - case NSH_PARSER_NORMAL : - case NSH_PARSER_IF: - default: - break; - - case NSH_PARSER_THEN: - return !vtbl->np.np_ifcond; - - case NSH_PARSER_ELSE: - return vtbl->np.np_ifcond; - } - return TRUE; -} - -/**************************************************************************** * Name: nsh_saveresult ****************************************************************************/ static inline int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, boolean result) { - vtbl->np.np_fail = result; - if (vtbl->np.np_state == NSH_PARSER_IF) + struct nsh_parser_s *np = &vtbl->np; + + if (np->np_st[np->np_ndx].ns_state == NSH_PARSER_IF) { - vtbl->np.np_fail = FALSE; - vtbl->np.np_ifcond = result; + np->np_fail = FALSE; + np->np_st[np->np_ndx].ns_ifcond = result; return OK; } else { - vtbl->np.np_fail = result; + np->np_fail = result; return result ? ERROR : OK; } } |