diff --git a/rootfs.manifest b/rootfs.manifest index 6ba2a86..093d855 100644 --- a/rootfs.manifest +++ b/rootfs.manifest @@ -499,6 +499,7 @@ file /bin/od file /bin/pagesize file /bin/passwd mode 04755 +file /bin/pdc file /bin/picoc file /bin/portio file /bin/pr diff --git a/src/cmd/pdc/COPYING b/src/cmd/pdc/COPYING new file mode 100644 index 0000000..5bb936f --- /dev/null +++ b/src/cmd/pdc/COPYING @@ -0,0 +1,343 @@ +Unless otherwise stated inside the file, all files +in this package are covered by the following license: + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/src/cmd/pdc/Makefile b/src/cmd/pdc/Makefile new file mode 100644 index 0000000..7f5c31b --- /dev/null +++ b/src/cmd/pdc/Makefile @@ -0,0 +1,29 @@ +TOPSRC = $(shell cd ../../..; pwd) +include $(TOPSRC)/target.mk +#include $(TOPSRC)/cross.mk +#CFLAGS = -DCROSS + +OBJS = pdc.o + +LDFLAGS += -g + +CFLAGS += -Werror -Wall -Os +CFLAGS += -DGCC_COMPAT -DHAVE_CPP_VARARG_MACRO_GCC + +all: pdc + +pdc: $(OBJS) + ${CC} ${LDFLAGS} -o pdc.elf $(OBJS) ${LIBS} + ${OBJDUMP} -S pdc.elf > pdc.dis + ${SIZE} pdc.elf + ${ELF2AOUT} pdc.elf $@ && rm pdc.elf + +clean: + rm -f *.o *.0 *.elf pdc *.dis tags *~ y.tab.[ch] + +install: all + install pdc $(DESTDIR)/bin/ + +pdc.o: pdc.y + $(YACC) -d $(YFLAGS) pdc.y + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o pdc.o y.tab.c diff --git a/src/cmd/pdc/Makefile-unix b/src/cmd/pdc/Makefile-unix new file mode 100644 index 0000000..f157e45 --- /dev/null +++ b/src/cmd/pdc/Makefile-unix @@ -0,0 +1,64 @@ +# +# Makefile +# +# The programmers desktop calculator. A desktop calculator supporting both +# shifts and mixed base inputs. +# +# Copyright (C) 2001, 2002, 2003, 2004, 2005 +# Daniel Thompson +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# + +TARGET = pdc + +CC = $(COMPILER_PREFIX)gcc +CFLAGS += -O2 -g + +STRIP = $(COMPILER_PREFIX)strip + + +ifndef WITHOUT_GCC +CFLAGS += -Wall +endif + +ifdef WITH_CMDEDIT +CFLAGS += -DHAVE_CMDEDIT +else + +# This assumes a dynamic link to libreadline.dll in .../bin. Defining +# WITHOUT_READLINE should have the normal effect. The .../lib part is just in +# case people do strange things to their layouts. +ifdef WIN32_HOME +CFLAGS += -I$(WIN32_HOME)/include -L$(WIN32_HOME)/lib -L$(WIN32_HOME)/bin +WITHOUT_NCURSES = 1 +TARGET := $(TARGET).exe +endif + +ifndef WITHOUT_READLINE +LDFLAGS += -lreadline +CFLAGS += -DHAVE_READLINE +endif +ifndef WITHOUT_NCURSES +LDFLAGS += -lncurses +endif + +endif + +all: $(TARGET) + +strip : $(TARGET) + $(STRIP) $(TARGET) + +$(TARGET) : y.tab.o + $(CC) $(CFLAGS) -o $@ y.tab.o $(LDFLAGS) + +y.tab.c : pdc.y + $(YACC) pdc.y + +clean : + $(RM) $(TARGET) y.tab.c *.o + diff --git a/src/cmd/pdc/README b/src/cmd/pdc/README new file mode 100644 index 0000000..944b42d --- /dev/null +++ b/src/cmd/pdc/README @@ -0,0 +1,74 @@ +PDC - the programmers desktop calculator +======================================== + +PDC is a desktop calculator similar to bc but with features designed +for use by programmers. In particular PDC supports most ANSI C +operators including bitwise operators and shifts. PDC also makes +dealing with mixed bases very easy since it supports contant pefixes +(eg 0xff, 0755). + +PDC is licenced under the GNU General Public Licence. The latest +version of PDC can be downloaded from http://www.redfelineninja.org.uk. +Jason Hood has ported PDC to DOS/Win32 (in five different ways). These +ports can be found at http://pdc.adoxa.cjb.net. + + +Features +-------- + + * mathematic operators +, -, *, /, % + * logic operators &&, ||, ! + * bitwise operators &, |, ^, ~, <<, >> + * uses ANSI C operator precedence + * prefix numbers with 0b, 0, 0d and 0x to support binary, octal, + decimal and hex regardless of input base + * output numbers in any number base of 16 or less + * functions to assist with 'bit bashing' + * command line expression evaluation + + +Building PDC +------------ + +PDC is supplied with a simple makefile. It should build with no +modifications on most Unix-like operating systems. However, you may need +to change the compilation flags (for example, to remove -Wall) if +you are not using gcc. + +PDC is tested most often on Solaris and GNU/Linux. It's written in YACC and C. + +PDC can also be built for Windows. The supplied Makefile has been written with +MinGW in mind, but other compilers may also work with some minor changes. To +build for Win32 using MinGW, the variable COMPILER_PREFIX must be defined to +the toolchain prefix - for example, "i586-mingw32msvc-". If building under +Win32, the variable WIN32_HOME should be used to point to where the required +include files and libraries may be found. + +By default PDC is built against the GNU readline library. If your system +does not have the library installed, set WITHOUT_READLINE on the make +command line (make WITHOUT_READLINE=1). You'll know if you don't have the +library due to all the errors. :-) A Win32 port of GNU readline can be +found at http://mingwrep.sf.net . + +DJGPP users will not have GNU readline but who have CmdEdit installed +can use that instead by setting HAVE_CMDEDIT. + + +Build examples +-------------- + +GNU/Linux: + make + +Solaris (generally Solaris does not have readline installed): + make WITHOUT_READLINE=1 + +MinGW/Win32 (assumes toolset headers in $HOME/win32/include and + readline.dll in $HOME/win32/bin ): + make WIN32_HOME=$HOME/win32 COMPILER_PREFIX=i586-mingw32msvc- + +Bugs and Feature Requests +-------------------------- + +Reproducable bugs and feature requests should be sent to +bugs-pdc@redfelineninja.org.uk. diff --git a/src/cmd/pdc/pdc.y b/src/cmd/pdc/pdc.y new file mode 100644 index 0000000..174bb3c --- /dev/null +++ b/src/cmd/pdc/pdc.y @@ -0,0 +1,918 @@ +/* + * pdc.y + * + * The programmers desktop calculator. A desktop calculator supporting both + * shifts and mixed base inputs. + * + * Copyright (C) 2001-2005, 2013 + * Daniel Thompson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +%{ +/* Includes ---------------------------------------------------------------- */ + +#include +#include +#include +#include +#include + +#if defined(HAVE_READLINE) +#include +#include +#endif + +#if defined(__DJGPP__) +#include +char** __crt0_glob_function(char *d) { return 0; } +#if !defined(HAVE_READLINE) +void __crt0_load_environment_file(char *d) { } +#endif +#endif + +#if defined(__MINGW32__) +int _CRT_glob = 0; +#endif + +/* Types ----------------------------------------------------------- */ + +typedef struct symbol { + const char *name; + const char *description; + int type; + union { + long var; + long (*func)(long); + } value; + struct symbol *next; +} symbol_t; + +/* Variables ------------------------------------------------------- */ + +symbol_t *symbol_table = NULL; +symbol_t initial_symbols[]; + +const char *version_string = "1.0"; + +int yyargc; +char **yyargv; + +/* are we taking input from the command line? */ +static int input_from_cmdline = 0; + +/* are we recovering from an internal error */ +static int internal_error = 0; + +#define LONGBITS (sizeof(long) * CHAR_BIT) +#define CHARMASK ((1 << CHAR_BIT) - 1) + +/* Function Prototypes --------------------------------------------- */ + +int yyerror(char *s); +int yylex(void); +int yyparse(); +symbol_t *getsym(const char *name); +symbol_t *putsym(const char *name, int type); +const char *num2str(unsigned long num, int base, int pad); +long print(long x); + +%} + +/* yylval's structure */ +%union { + long integer; + symbol_t *symbol; +} + +%token INTEGER +%token VARIABLE FUNCTION +%type expression + +/* operators have C conventions for precedence */ +%right '=' INC DEC MUL DIV MOD AND XOR OR LEFT RIGHT +%right '?' ':' +%left LOGICAL_OR +%left LOGICAL_AND +%left '|' +%left '^' +%left '&' +%left EQ NE +%left '<' LE '>' GE +%left LEFT_SHIFT RIGHT_SHIFT +%left '+' '-' +%left '*' '/' '%' +%left '!' '~' NEG + + +%% /* YACC grammar follows */ + +input: /* empty */ + | input line +; + +line : expression '\n' { getsym("ans")->value.var = print($1); } + | expression ',' { getsym("ans")->value.var = $1; } + | '\n' /* do nothing */ + | error '\n' { yyerrok; } +; + +expression: + INTEGER { $$ = $1; } + | VARIABLE { $$ = $1->value.var; } + | FUNCTION '(' expression ')' { $$ = (*($1->value.func))($3); } + | FUNCTION expression { $$ = (*($1->value.func))($2); } + | FUNCTION { $$ = (*($1->value.func))(getsym("ans")->value.var); } + | VARIABLE '=' expression { $$ = $1->value.var = $3; } + | VARIABLE INC expression { $$ = $1->value.var += $3; } + | VARIABLE DEC expression { $$ = $1->value.var -= $3; } + | VARIABLE MUL expression { $$ = $1->value.var *= $3; } + | VARIABLE DIV expression { if (0 != $3) { + $$ = $1->value.var /= $3; + } else { + yyerror("divide by zero error"); + internal_error = 1; + $$ = 0; + } + } + | VARIABLE MOD expression { $$ = $1->value.var %= $3; } + | VARIABLE AND expression { $$ = $1->value.var &= $3; } + | VARIABLE XOR expression { $$ = $1->value.var ^= $3; } + | VARIABLE OR expression { $$ = $1->value.var |= $3; } + | VARIABLE LEFT expression { $$ = $1->value.var <<= $3; } + | VARIABLE RIGHT expression { $$ = $1->value.var >>= $3; } + | expression '?' expression ':' expression + { $$ = $1 ? $3 : $5; } + | expression '+' expression { $$ = $1 + $3; } + | expression '-' expression { $$ = $1 - $3; } + | expression '|' expression { $$ = $1 | $3; } + | expression '^' expression { $$ = $1 ^ $3; } + | expression '*' expression { $$ = $1 * $3; } + | expression '/' expression { if (0 != $3) { + $$ = $1 / $3; + } else { + yyerror("divide by zero error"); + internal_error = 1; + $$ = 0; + } + } + | expression '%' expression { $$ = $1 % $3; } + | expression '&' expression { $$ = $1 & $3; } + | expression '<' expression { $$ = $1 < $3; } + | expression '>' expression { $$ = $1 > $3; } + | expression EQ expression { $$ = $1 == $3; } + | expression LE expression { $$ = $1 <= $3; } + | expression GE expression { $$ = $1 >= $3; } + | expression NE expression { $$ = $1 != $3; } + | '~' expression { $$ = ~$2; } + | '-' expression %prec NEG { $$ = -$2; } + | expression LEFT_SHIFT expression + { $$ = $1 << $3; } + | expression RIGHT_SHIFT expression + { $$ = $1 >> $3; } + | expression LOGICAL_AND expression + { $$ = $1 && $3; } + | expression LOGICAL_OR expression + { $$ = $1 || $3; } + | '!' expression { $$ = !$2; } + | '(' expression ')' { $$ = $2; } +; + +%% + +/* Functions --------------------------------------------------------------- */ + +#if defined(HAVE_READLINE) +int yygetc(void) +{ + static char *line, *pos; + + if (!line) { + line = pos = readline("> "); + if (!line) { + return EOF; + } + + /* if the line has any text in it, save it in the history */ + if ('\0' != *line) { + add_history(line); + } + } + + if ('\0' == *pos) { + free(line); + line = 0; + return '\n'; + } + + return *pos++; +} +#elif defined(HAVE_CMDEDIT) +/* Use the editing and history features provided by CmdEdit. */ +#include +#include +#include +int yygetc(void) +{ + static char line[256], *pos = line; + + if (pos == line) { + fputs("> ", stdout); + fflush(stdout); + __dpmi_regs regs; + regs.h.ah = 0x0a; /* buffered input */ + regs.x.ds = __tb >> 4; + regs.x.dx = __tb & 0x0f; + _farpokeb(_dos_ds, __tb, 255); + _farpokeb(_dos_ds, __tb+1, 0); + __dpmi_int(0x21, ®s); + dosmemget(__tb+2, 256, line); + putchar('\n'); + pos = line; + if ('\x1a' == *pos) { + return EOF; + } + } + + if ('\r' == *pos) { + pos = line; + return '\n'; + } + + return *pos++; +} +#else +int yygetc(void) +{ + static int lastch = '\n'; + + /* manage the prompt */ + if ('\n' == lastch) { + printf("> "); + fflush(stdout); + } + + lastch = getchar(); + return lastch; +} +#endif + +int yyungetc; +int yygetchar(void) +{ + if ('\0' != yyungetc) { + int ch = yyungetc; + yyungetc = '\0'; + return ch; + } + + if (input_from_cmdline) { + static int arg=1, pos=0; + + if (arg >= yyargc) { + return (arg++ == yyargc ? '\n' : EOF); + } + + if ('\0' == yyargv[arg][pos]) { + arg++; + pos = 0; + return ' '; + } + + return yyargv[arg][pos++]; + } + + return yygetc(); +} + +int yyerror(char *s) +{ + printf("%s\n", s); + fflush(stdout); + return 0; +} + +int yylex(void) +{ + int c, i; + + /* ignore whitespace */ + do { + c = yygetchar(); + } while (strchr(" \t", c)); + + /* handle end of input */ + if (EOF == c) { + return 0; + } + + /* handle numeric types */ + if (isdigit(c)) { + int base; + int nDigits; + + /* determine the base of this number */ + if (c != '0') { + base = getsym("ibase")->value.var; + yyungetc = c; + } else { + c = yygetchar(); + switch(c) { + case 'd': + case 'D': + base = 10; + break; + case 'x': + case 'X': + base = 16; + break; + case 'b': + case 'B': + base = 2; + break; + default: + base = 8; + yyungetc = c; + } + } + + yylval.integer = 0; + nDigits = 0; + c = yygetchar(); + while (EOF != c && isxdigit(c)) { + unsigned digit = (c <= '9') ? + (c & 0xf) : + (((c - 'A') & 7) + 10); + if (digit >= base) { + break; + } + + nDigits++; + yylval.integer *= base; + yylval.integer += digit; + + c = yygetchar(); + } + + switch (c) { + case 'K': + yylval.integer *= 1024; + break; + case 'M': + yylval.integer *= 1024*1024; + break; + case 'G': + yylval.integer *= 1024*1024*1024; + break; + case 'b': + case 'B': + case '_': + yylval.integer = 1l << yylval.integer; + break; + default: + if (0 == nDigits && 2 == base) + yylval.integer = 1; + yyungetc = c; + } + + return INTEGER; + } + + /* handle single quoted strings including multi-character + * constants (a common extension to ANSI C) + */ + if ('\'' == c) { + yylval.integer = 0; + + for (c = yygetchar(); EOF != c && '\'' != c; c = yygetchar()) { + yylval.integer = (yylval.integer << 8) + (c & 255); + } + + return INTEGER; + } + + /* handle identifiers */ + if (isalpha(c)) { + symbol_t *sym; + static char *buf = NULL; /* this is allocated only once */ + static int length = 0; + + if (NULL == buf) { + length = 40; + buf = malloc(length + 1); + } + + i = 0; + do { + /* grow the buffer if it is too small */ + if (i == length) { + length *= 2; + buf = realloc(buf, length +1); + } + + buf[i++] = c; + c = yygetchar(); + } while ((EOF != c) && isalnum(c)); + + yyungetc = c; + buf[i] = '\0'; + + /* look up (or generate) the symbol */ + if (NULL == (sym = getsym(buf))) { + sym = putsym(buf, VARIABLE); + } + yylval.symbol = sym; + return sym->type; + } + + /* check for the shift and logical operators */ + if (strchr("<>&|=+-*/%^!", c)) { + int d = yygetchar(); + if (c == d) { + switch (c) { + case '<': + case '>': + d = yygetchar(); + if ('=' == d) { + return ('<' == c ? LEFT : RIGHT); + } + yyungetc = d; + return ('<' == c ? LEFT_SHIFT : RIGHT_SHIFT); + case '&': return LOGICAL_AND; + case '|': return LOGICAL_OR; + case '=': return EQ; + } + } else if (d == '=') { + switch (c) { + case '<': return LE; + case '>': return GE; + case '!': return NE; + case '+': return INC; + case '-': return DEC; + case '*': return MUL; + case '/': return DIV; + case '%': return MOD; + case '&': return AND; + case '^': return XOR; + case '|': return OR; + } + } else { + yyungetc = d; + } + } + + /* this is a single character terminal */ + return c; +} + +long defaultfunc(long i) +{ + fprintf(stderr, "internal error\n"); + exit(0); + + return 0; +} + +symbol_t *putsym(const char *name, int type) +{ + symbol_t *sym; + + sym = (symbol_t*) malloc(sizeof(*sym)); + if (NULL == sym) { + return NULL; + } + + sym->name = strdup(name); + if (NULL == sym->name) { + free(sym); + return NULL; + } + + sym->type = type; + switch(type) { + case VARIABLE: + sym->value.var = 0; + break; + case FUNCTION: + sym->value.func = defaultfunc; + break; + } + + /* Can't think of a good way to set that at present. */ + sym->description = NULL; + sym->next = symbol_table; + symbol_table = sym; + + return sym; +} + +symbol_t *getsym(const char *name) +{ + symbol_t *p; + + for (p = symbol_table; p != NULL; p = p->next) { + if (0 == strcmp(p->name, name)) { + return p; + } + } + + return NULL; +} + +const char *num2str(unsigned long num, int base, int pad) { + static const char lookup[] = "0123456789abcdef"; + static char str[LONGBITS + 1]; + char *pStr, *padStr; + + /* check for unsupported bases */ + if (base < 2 || base >= sizeof(lookup)) { + printf("(bad obase, assuming base 10)\n\t"); + base = 10; + } + + /* and illegal pad lengths */ + if (pad < 1 || pad > LONGBITS) { + printf("(bad pad, assuming pad 1)\n\t"); + pad = 1; + } + + /* pad str with zeros */ + memset(str, '0', sizeof(str)); + + pStr = &str[sizeof(str)]; + *--pStr = '\0'; + padStr = pStr - pad; + + do { + *--pStr = lookup[num % base]; + num /= base; + } while (num); + + return (padStr < pStr ? padStr : pStr); +} + +long ascii(long x) +{ + long w; + int b; + + printf("\t'"); + if (0 == x) { + printf("\\0"); + } else { + /* ignore leading NILs */ + b = LONGBITS / CHAR_BIT; + w = x; + while (0 == ((w >> (LONGBITS - CHAR_BIT)) & CHARMASK)) { + --b; + w <<= CHAR_BIT; + } + for (; b > 0; w <<= CHAR_BIT, --b) { + char c = (w >> (LONGBITS - CHAR_BIT)) & CHARMASK; + if (0 == c) { + printf("\\0"); + } else { + printf(isprint(c) ? "%c" : "\\x%02x", c); + } + } + } + printf("'\n\n"); + + return x; +} + +long bitcnt(long x) +{ + long b; + for (b=0; x!=0; b++) { + x &= x-1; /* clear least significant (set) bit */ + } + return b; +} + +long bitfield(long x) +{ + symbol_t *N = getsym("N"); + long result; + + if (0 == N->value.var) { + printf("WARNING: N is zero - automatically setting N to ans\n\n"); + N->value.var = getsym("ans")->value.var; + } + + result = N->value.var & ~(-1l << x); + N->value.var >>= x; + + /* force logical shift on all machines */ + N->value.var &= ~(-1l << (LONGBITS - x)); + + return result; +} + +long decompose(long x) +{ + char *separator = ""; + long i; + + if (0 != x) { + printf("\t"); + + for (i = LONGBITS - 1; i >= 0; i--) { + if (0 != (x & (1l<= 0; i--) { + if (0 != (x & (1l<> 24 & 0x000000ff) | + (d >> 8 & 0x0000ff00) | + (d << 8 & 0x00ff0000) | + (d << 24 & 0xff000000); +} + +long labs(long d) +{ + if (d < 0) + return -d; + return d; +} + +long quit(long ret) +{ + exit((int) ret); + return 0; +} + +long print(long x) +{ + long obase = getsym("obase")->value.var; + int pad = abs(getsym("pad")->value.var); + + if (internal_error) { + internal_error = 0; + return 0; + } + + if (!input_from_cmdline) { + printf("\t"); + } + + /* print the prefixes */ + switch(obase) { + case 16: + printf("0x"); + break; + case 10: + break; + case 8: + printf("0"); + break; + case 2: + printf("0b"); + break; + case 0: + case 1: + break; + default: + printf("[base %ld] ", obase); + } + + /* now print the actual values */ + switch(obase) { + case 10: + /* print base 10 values directly to keep signedness */ + printf("%0*ld\n", pad, x); + break; + case 1: + /* special case base 1 (print dex, hex and binary) */ + printf("%0*ld\t[0x%0*lx]\t[0b%s]\n", pad, x, pad, x, num2str(x, 2, LONGBITS)); + break; + case 0: + /* special case base 0 (print dec and hex) */ + printf("%0*ld\t[0x%0*lx]\n", pad, x, pad, x); + break; + default: + printf("%s\n", num2str(x, obase, pad)); + } + + return x; +} + +void print_help(long mode) +{ + printf( +"pdc %s - the programmers desktop calculator\n" +"\n" +"Copyright (C) 2001-2005, 2013 Daniel Thompson \n" +"This is free software with ABSOLUTELY NO WARRANTY.\n" +"For details type `warranty'.\n" +"\n", + version_string); + + if (1 == mode) { + symbol_t *sym; + printf( +"Contributors:\n" +" Daniel Thompson \n" +" Paul Walker \n" +" Jason Hood \n" +"\n" + ); + printf("Variables:\n"); + for (sym=initial_symbols; NULL != sym->name; sym++) { + if (VARIABLE == sym->type) { + printf(" %-9s - %s\n", sym->name, sym->description); + } + } + printf("\nFunctions:\n"); + for (sym=initial_symbols; NULL != sym->name; sym++) { + if (FUNCTION == sym->type) { + printf(" %-9s - %s\n", sym->name, sym->description); + } + } + printf("\n"); + + if (input_from_cmdline) { + printf( +"Usage:\n" +" pdc [] [, ] ...\n" +"\n" +" Without arguments pdc enters interactive mode; otherwise it evaluates its\n" +" arguments and prints the result. Expressions are separated using the ,\n" +" operator (e.g. 'pdc obase=2, 4*12'). Only the last expression evaluated\n" +" will be printed automatically. Use the print function to display\n" +" intermediate values if required.\n" +"\n" + ); + } + } + + if (2 == mode) { + printf( +"This program is free software; you can redistribute it and/or modify\n" +"it under the terms of the GNU General Public License as published by\n" +"the Free Software Foundation; either version 2 of the License, or\n" +"(at your option) any later version.\n" +"\n" +"This program is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n" +"\n" +"You should have received a copy of the GNU General Public License along\n" +"with this program; if not, write to the Free Software Foundation, Inc.,\n" +"51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" +"\n" +"Or see https://www.gnu.org/licenses/old-licenses/gpl-2.0.html\n" +"\n" + ); + } + if (3 == mode) { + symbol_t *sym; + + printf("Compiled: "__TIME__" "__DATE__"\n"); + printf("Built-in symbols: "); + for (sym=initial_symbols; NULL != sym->name; sym++) { + printf(" %s%s", sym->name, (FUNCTION == sym->type ? "()" : "")); + } + printf("\n\n"); + } + +} + +long help(long ans) +{ + print_help(1); + return ans; +} + +long version(long ans) +{ + print_help(3); + return ans; +} + +long warranty(long ans) +{ + print_help(2); + return ans; +} + +#define BASE_FN(name, base) \ +long name(long ans) \ +{ \ + getsym("obase")->value.var = base; \ + return ans; \ +} + +BASE_FN(dechex, 0) +BASE_FN(dxb, 1) +BASE_FN(bin, 2) +BASE_FN(oct, 8) +BASE_FN(dec, 10) +BASE_FN(hex, 16) + +/* Print routine in the help function isn't too clever, so VARIABLE and + * FUNCTION should be grouped together, otherwise the display looks a + * bit weird. Not hard to fix, but probably more work than it's worth. + */ +symbol_t initial_symbols[] = { +{ "ans", "the result of the previous calculation", VARIABLE, { 0 }, NULL }, +{ "ibase", "the default input base (to force decimal use 0d10)", VARIABLE, { 10 }, NULL }, +{ "obase", "the output base (set to zero or one for combined bases)", VARIABLE, { 0 }, NULL }, +{ "pad", "the amount of zero padding used when displaying numbers", VARIABLE, { 1 }, NULL }, +{ "N", "global variable used by the bitfield function", VARIABLE, { 0 }, NULL }, +{ "abs", "get the absolute value of x", FUNCTION, { (long) labs }, NULL }, +{ "ascii", "convert x into a character constant", FUNCTION, { (long) ascii }, NULL }, +{ "bin", "change output base to binary", FUNCTION, { (long) bin }, NULL }, +{ "bitcnt", "get the population count of x", FUNCTION, { (long) bitcnt }, NULL }, +{ "bitfield", "extract the bottom x bits of N and shift N", FUNCTION, { (long) bitfield}, NULL }, +{ "bits", "alias for decompose", FUNCTION, {(long) decompose}, NULL }, +{ "dec", "set the output base to decimal", FUNCTION, { (long) dec }, NULL }, +{ "decompose", "decompose x into a list of bits set", FUNCTION, {(long) decompose}, NULL }, +{ "default", "set the default output base (decimal and hex)", FUNCTION, { (long) dechex }, NULL }, +{ "dxb", "output in decimal, hex and binary", FUNCTION, { (long) dxb }, NULL }, +{ "help", "display this help message", FUNCTION, { (long) help }, NULL }, +{ "hex", "change output base to hex", FUNCTION, { (long) hex }, NULL }, +{ "lssb", "get the least significant set bit in x", FUNCTION, { (long) lssb }, NULL }, +{ "mssb", "get the most significant set bit in x", FUNCTION, { (long) mssb }, NULL }, +{ "oct", "change output base to octal", FUNCTION, { (long) oct }, NULL }, +{ "print", "print an expression (useful for command line work)", FUNCTION, { (long) print }, NULL }, +{ "quit", "leave pdc", FUNCTION, { (long) quit }, NULL }, +{ "swap32", "perform a 32-bit byte swap", FUNCTION, { (long) swap32 }, NULL }, +{ "version", "display version information", FUNCTION, { (long) version }, NULL }, +{ "warranty", "display warranty and licencing information", FUNCTION, { (long) warranty}, NULL }, +{ "K", "Defaults to KiB (1024 bytes)", VARIABLE, { 1024 }, NULL }, +{ "M", "Defaults to MiB (1048576 bytes)", VARIABLE, { 1024 * 1024 }, NULL }, +{ "G", "Defaults to GiB (1073741824 bytes)", VARIABLE, { 1073741824 }, NULL }, +{ NULL, "", 0, { 0 }, NULL } +}; + +int main(int argc, char *argv[]) +{ + int i; + + /* setup the initial symbol table */ + for (i=1; NULL != initial_symbols[i].name; i++) { + initial_symbols[i].next = &initial_symbols[i-1]; + } + symbol_table = &initial_symbols[i-1]; + + /* run in non-interactive mode if we have command line arguments */ + if (argc > 1) { + input_from_cmdline = 1; + yyargc = argc; + yyargv = argv; + } else { + print_help(0); + } + + /* run the calculator */ + yyparse(); + +#if defined(HAVE_READLINE) || (!defined(__DJGPP__) && !defined(__MINGW32__)) + if (!input_from_cmdline) { + /* shutdown cleanly after a ^D */ + printf("\n"); + } +#endif + + return 0; +}