davidgiven / ack Goto Github PK
View Code? Open in Web Editor NEWThe Amsterdam Compiler Kit
Home Page: http://tack.sf.net
License: Other
The Amsterdam Compiler Kit
Home Page: http://tack.sf.net
License: Other
THE AMSTERDAM COMPILER KIT V6.1pre1 =================================== © 1987-2005 Vrije Universiteit, Amsterdam 2022-08-19 INTRODUCTION ============ The Amsterdam Compiler Kit is a complete compiler toolchain consisting of front end compilers for a number of different languages, code generators, support libraries, and all the tools necessary to go from source code to executable on any of the platforms it supports. This is an early prerelease of the apocryphal version 6.1 release. Not a lot is supported, the build mechanism needs work, and a lot of things are probably broken. However, what's there should be sufficient to get things done and to evaluate how the full 6.1 release should work. SUPPORT ======= Languages: ANSI C, B, Pascal, Modula 2, Basic. K&R is supported via the ANSI C compiler. Platforms: pc86 produces bootable floppy disk images for 8086 PCs linux386 produces ELF executables for PC Linux systems linux68k produces ELF executables for m68020 Linux systems linuxppc produces ELF executables for PowerPC Linux systems linuxmips produces ELF executables for little-endian MIPS32r2 Linux systems cpm produces i80 CP/M .COM files rpi produces Raspberry Pi GPU binaries pdpv7 produces PDP/11 V7 Unix binaries msdos86 produces i86 MS-DOS .COM files msdos386 produces i386 MS-DOS 32-bit DPMI .EXE files INSTALLATION ============ The version 5.0 build mechanism has been completely rewritten. Installation ought to be fairly straightforward. It will build on Unixishes including Linux, OSX, and Windows using MSYS2 and mingw32. Requirements: - an ANSI C compiler. This defaults to gcc. You can change this by setting the CC make variable. - flex and yacc. - GNU make. - Lua (any version) with the lua-posix library installed. - (optionally) ninja; if you've got this, this will be autodetected and give you faster builds. - about 115MB free in /tmp (or some other temporary directory). - about 15MB in the target directory. Instructions: - edit the Makefile. There's a small section at the top where you can change the configuration. Probably the only one you may want to edit is PREFIX, which changes where the ACK installs to. - Run: make ...from the command line. This will do the build. The make system is fully parallelisable. If you have a multicore system, install ninja and it'll use all your cores. If you don't have ninja, you can still use make for parallel builds with: make -r -j8 # or however many cores you have ...but frankly, I recommend ninja. - Run: sudo make install ...from the command line. This will install the ACK in your PREFIX directory (by default, /usr/local). The ACK should now be ready to use. USAGE ===== Currently I haven't sorted out all the documentation --- it's supplied in the distribution, but not all of it gets installed yet --- so here is a quickstart guide. The main command to use is 'ack'. This invokes the compiler and the linker. Some useful options include: -m<platform> build for the specified platform -o <file> specifies the output file -c produce a .o file -c.s produce a .s assembly file -O enable optimisation (optimisation levels go up to 6) -ansi compile ANSI C (when using the C compiler) -v be more verbose (repeatable) <file> build file ack figures out which language to use from the file extension: .c C (ANSI or K&R) .b the PDP-11 dialect of B .bas Basic .mod Modula-2 .ocm Occam 1 .p Pascal .o object files .s assembly files .e ACK intermediate code assembly files For further information, see the man page (which actually does get installed, but is rather out of date). There are some (known working) example programs in the 'examples' directory. A sample command line is: ack -mlinux386 -O examples/paranoia.c GOTCHAS ======= There are some things you should be aware of. - Look at plat/<PLATFORMNAME>/README for information about the supported platforms. - The library support is fairly limited; for C, it's at roughly the ANSI C level, and for the other languages it's similar. - When compiling languages other than C, the ACK will usually look at the first character of the file. If it's a #, then the file will be run through the C preprocessor anyway. - BSD systems may need to up the number of file descriptors (e.g. 'ulimit -n 200') before the ACK will compile. - The ACK uses its own .o format. You won't be able to mix the ACK's object files and another compiler's. - When compiling together multiple B source files, you need to do some extra work to initialise them properly otherwise your program will crash on startup; see the ack(1) and abmodules(1) man pages. - The distribution contains *everything*, including the weird, ancient, archaic stuff that doesn't work any more and never will, such as the int EM interpreter and the assembler-linkers. Only some of it builds. Look for build.lua files. DISCLAIMER ========== The ACK is mature, well-tested software, but the environment in which it was developed for and tested under is rather different from that available on today's machines. There will probably be little in the way of logical bugs, but there may be many compilation and API bugs. If you wish to use the ACK, *please* join the mailing list. We are interested in any reports of success and particularly, failure. If it does fail for you, we would love to know why, in as much detail as possible. Bug fixes are even more welcome. The ACK is licensed under a BSD-like license. Please see the 'Copyright' file for the full text. You can find the mailing list on the project's web site: http://tack.sourceforge.net/ Please enjoy. David Given (davidgiven on Github) [email protected] 2018-09-18
mach/m68k2/as/mach4.c:287]: (style) Expression '(X & 0x38) == 0x1' is always false.
mach/m68k2/as/mach4.c:298]: (style) Expression '(X & 0x38) == 0x1' is always false.
I was looking at https://travis-ci.org/davidgiven/ack and noticed that clang's warnings look exactly like gcc's warnings. That's because the clang build uses gcc, not clang. The sequence of commands is
$ export CC=clang
$ clang --version
$ make PREFIX=/tmp/acki +ack
but the Makefile's CC = gcc
takes precedence over the environment's CC=clang
.
The following Pascal program causes a linker error, because its procedure malloc conflicts with malloc in libc:
program callmalloc(output);
var p : ^integer;
procedure malloc;
begin
writeln('pass');
end;
begin
new(p);
malloc;
end.
$ ack -mlinuxppc -o callmalloc callmalloc.p
led: /home/kernigh/park/ack-build/staging/share/ack/linuxppc/libc.a(malloc.o): _malloc: multiply defined (error)
This only happens because Pascal's new uses libc's malloc (since c084f9f). If I delete the new(p);
line and the p variable, then the program prints pass.
This kind of name conflict seems to be caused by recent changes to ACK. Older ACK did more to prevent name conflicts between Pascal and C. In older ACK, Pascal programs did not link to libc. Old descr files like lib/i386/descr
don't link libc to Pascal programs, but new descr files like plat/linux386/descr
do link libc.
Also in older ack, libsys had alternate names for some system calls. These names had underscores, like _exit
and _times
. They hid from Pascal because Pascal has no underscores in its names. Pascal's libpc called the hidden names. Commit 1c83baa in 2007, and later commits, switched some calls to the regular names like close
and open
, but the regular names can conflict with Pascal programs.
It's been a long time since I tried the ACK. I have installed luaposix and ninja, tweaked the top-level Makefile to run lua51 (not lua5.1), and I'm now trying to build 8c94b13. I'm running OpenBSD 6.0 on amd64. Build fails when ego gets a signal:
[945/2942] ACKDIR=/tmp/ack-build/stagi...obj/plat/linux386/include/headers -O6
FAILED: /tmp/ack-build/obj/lang/cem/libcc.ansi/lib_linux386/memcpy/memcpy.o
ACKDIR=/tmp/ack-build/staging /tmp/ack-build/staging/bin/ack -mlinux386 -c -o /tmp/ack-build/obj/lang/cem/libcc.ansi/lib_linux386/memcpy/memcpy.o lang/cem/libcc.ansi/string/memcpy.c -I/tmp/ack-build/obj/lang/cem/libcc.ansi/headers/headers -I/tmp/ack-build/obj/plat/linux386/include/headers -O6
ego: /tmp/ack-build/staging/lib/ack/ego/cf got a unix signal
[946/2942] ACKDIR=/tmp/ack-build/stagi...obj/plat/linux386/include/headers -O6
FAILED: /tmp/ack-build/obj/lang/cem/libcc.ansi/lib_linux386/strncmp/strncmp.o
ACKDIR=/tmp/ack-build/staging /tmp/ack-build/staging/bin/ack -mlinux386 -c -o /tmp/ack-build/obj/lang/cem/libcc.ansi/lib_linux386/strncmp/strncmp.o lang/cem/libcc.ansi/string/strncmp.c -I/tmp/ack-build/obj/lang/cem/libcc.ansi/headers/headers -I/tmp/ack-build/obj/plat/linux386/include/headers -O6
ego: /tmp/ack-build/staging/lib/ack/ego/cf got a unix signal
[947/2942] ACKDIR=/tmp/ack-build/stagi...obj/plat/linux386/include/headers -O6
FAILED: /tmp/ack-build/obj/lang/cem/libcc.ansi/lib_linux386/tzset/tzset.o
ACKDIR=/tmp/ack-build/staging /tmp/ack-build/staging/bin/ack -mlinux386 -c -o /tmp/ack-build/obj/lang/cem/libcc.ansi/lib_linux386/tzset/tzset.o lang/cem/libcc.ansi/time/tzset.c -I/tmp/ack-build/obj/lang/cem/libcc.ansi/headers/headers -I/tmp/ack-build/obj/plat/linux386/include/headers -O6
ego: /tmp/ack-build/staging/lib/ack/ego/cf got a unix signal
ninja: build stopped: subcommand failed.
gmake: *** [Makefile:79: +ack] Error 1
Looking at the last core dump:
$ gdb /tmp/ack-build/staging/lib/ack/ego/cf cf.core
GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "amd64-unknown-openbsd6.0"...
Core was generated by `cf'.
Program terminated with signal 10, Bus error.
Loaded symbols for /tmp/ack-build/staging/lib/ack/ego/cf
Reading symbols from /usr/lib/libc.so.88.0...done.
Loaded symbols for /usr/lib/libc.so.88.0
Reading symbols from /usr/libexec/ld.so...done.
Loaded symbols for /usr/libexec/ld.so
#0 putunit (kind=Variable "kind" is not available.
) at util/ego/share/put.c:436
436 Ldeleteset(b->b_loops);
(gdb) bt
#0 putunit (kind=Variable "kind" is not available.
) at util/ego/share/put.c:436
#1 0x00001c55fec01ca0 in main (argc=Variable "argc" is not available.
) at util/ego/cf/cf.c:596
(gdb) print b
$1 = 0xdfdfdfdfdfdfdfdf
Looks like b is in freed memory. The 0xdf bytes are probably junk from OpenBSD's free(), see malloc.conf(5). I'm now looking for the bug in ego's code.
Months ago on 2017-04-27, Rune mailed tack-devel to report this bug:
https://sourceforge.net/p/tack/mailman/message/35809953/
@davidgiven reproduced the bug and pointed to the peephole optimiser (util/opt).
I create this GitHub issue now so I have a bug number to create tests/plat/bugs/bug-??-notvar_var_e.c. I will be testing this change:
diff --git a/util/opt/patterns b/util/opt/patterns
index 8d949dfd8..34bcc760a 100644
--- a/util/opt/patterns
+++ b/util/opt/patterns
@@ -641,13 +641,13 @@ lol lol bne $1==$2 :
loe loe bne $1==$2 :
lil lil bne $1==$2 :
-lol lol teq $1==$2 : loc 1
-loe loe teq $1==$2 : loc 1
-lil lil teq $1==$2 : loc 1
+lol lol cms teq $1==$2 && $3==w : loc 1
+loe loe cms teq $1==$2 && $3==w : loc 1
+lil lil cms teq $1==$2 && $3==w : loc 1
-lol lol tne $1==$2 : loc 0
-loe loe tne $1==$2 : loc 0
-lil lil tne $1==$2 : loc 0
+lol lol cms tne $1==$2 && $3==w : loc 0
+loe loe cms tne $1==$2 && $3==w : loc 0
+lil lil cms tne $1==$2 && $3==w : loc 0
lol loc CBO stl $3==w && $1==$4 : loc $2 lol $1 CBO w stl $4
lol loe CBO stl $3==w && $1==$4 : loe $2 lol $1 CBO w stl $4
It returns a long; if time_t won't fit in a long, like on i386 OpenBSD, it mangles the result.
sys_time() needs to go.
If I run make I get the following errors:
util/LLgen+llgen/main
util/LLgen+llgen
lang/basic/src+llgen
"/home/fcaruso/ACK_INSTALL/ack/lang/basic/src/basic.g", line 65: (Warning) terminal DBLVALUE not used
"/home/fcaruso/ACK_INSTALL/ack/lang/basic/src/basic.g", line 67: (Warning) terminal UNARYSYM not used
"/home/fcaruso/ACK_INSTALL/ack/lang/basic/src/basic.g", line 77: (Warning) terminal BOOLOP not used
"/home/fcaruso/ACK_INSTALL/ack/lang/basic/src/basic.g", line 83: (Warning) terminal LESYM not used
"/home/fcaruso/ACK_INSTALL/ack/lang/basic/src/basic.g", line 84: (Warning) terminal GESYM not used
"/home/fcaruso/ACK_INSTALL/ack/lang/basic/src/basic.g", line 85: (Warning) terminal NESYM not used
"/home/fcaruso/ACK_INSTALL/ack/lang/basic/src/basic.g", line 86: (Warning) terminal UNARYMINUS not used
lang/basic/src+tokentab_h
lang/basic/src/maketokentab: line 3: ed: command not found
make[1]: *** [/tmp/ack-build/build.make:354: lang/basic/src+tokentab_h-IMPL] Error 127
make[1]: Leaving directory '/home/fcaruso/ACK_INSTALL/ack'
make: *** [Makefile:102: build-plus-goals] Error 2
...such as Windows through Cygwin.
There are problems where files like scope.C are preprocessed and scope.c produced. Sample log attached.
The following program prints "pass" with gcc but "fail" with ack:
#include <stdio.h>
void f(void) {}
char *g = (char *)f + 11;
int main(void) {
char *h = g - 11;
if (h == (char *)f) {
puts("pass");
return 0;
} else {
puts("fail");
return 1;
}
}
In OpenBSD/amd64: ack -mlinuxppc -o cka ckpointer.c
In Debian Linux/powerpc:
$ gcc -o ckg ckpointer.c
$ ./cka
fail
$ ./ckg
pass
The bug is with char *g = (char *)f + 11;
where g is a global variable and f is a function. Now gcc is correct, but ack silently loses the 11 and effectively does char *g = (char *)f;
. After running ack -c.e ckpointer.c
, I can see g defined as
g
con $f
To get this bug, f must be a function, and I must cast it to another pointer type like char *. If I don't cast f, or if I cast f to an integer type, then ack gives an error for an illegal initializer.
ACK failed to compile in CentOS 7, following is a snippet of error messages:
/tmp/ack-build/obj/util/ncgg/cggparser/y.tab.h: In function ‘enterkeyw’:
/tmp/ack-build/obj/util/ncgg/cggparser/y.tab.h:161:66: error: ‘ADDR’ undeclared (first use in this function)
int yyparse ();
^
/tmp/ack-build/obj/util/ncgg/cggparser/y.tab.h:161:66: note: each undeclared identifier is reported only once for ea
ch function it appears in
/tmp/ack-build/obj/util/ncgg/cggparser/y.tab.h:162:71: error: ‘COERCIONS’ undeclared (first use in this function)
#endif
^
/tmp/ack-build/obj/util/ncgg/cggparser/y.tab.h:163:74: error: ‘INSTRUCTIONS’ undeclared (first use in this function)
#endif /* ! YYPARSE_PARAM */
^
/tmp/ack-build/obj/util/ncgg/cggparser/y.tab.h:164:65: error: ‘INT’ undeclared (first use in this function)
^
/tmp/ack-build/obj/util/ncgg/cggparser/y.tab.h:165:67: error: ‘MOVES’ undeclared (first use in this function)
#endif /* !YY_YY_TMP_ACK_BUILD_OBJ_UTIL_NCGG_CGGPARSER_Y_TAB_H_INCLUDED */
^
/tmp/ack-build/obj/util/ncgg/cggparser/y.tab.h:166:70: error: ‘PATTERNS’ undeclared (first use in this function)
...
If I build ack, then edit any file that llgen takes as input, then the build system gets stuck in infinite rebuilds. These commands reproduce the problem:
$ gmake
$ touch lang/pc/comp/statement.g
$ gmake
$ gmake
I'm using ninja. The first gmake
builds everything. After touching statement.g, the second gmake
seems to succeed. It runs llgen and rebuilds everything that depends on llgen's output. The third gmake
repeats the actions of the second gmake
, by running llgen again and rebuilding the same things.
To stop the infinite rebuilds and work around this problem, I run gmake clean
. The problem recurs whenever I edit a .g file, or when I edit a .c file and the build system generates a .g file from the .c file.
I observe that llgen succeeds without touching some of its output files; this might be confusing ninja.
$ ls -l lang/pc/comp/statement.g
-rw-r--r-- 1 kernigh kernigh 9276 Nov 14 14:53 lang/pc/comp/statement.g
$ cd ../ack-build/obj
$ ls -l lang/pc/comp/llgen/
total 312
-rw-r--r-- 1 kernigh kernigh 14207 Nov 13 22:15 Lpars.c
-rw-r--r-- 1 kernigh kernigh 959 Nov 13 22:15 Lpars.h
-rw-r--r-- 1 kernigh kernigh 62723 Nov 13 22:15 declar.c
-rw-r--r-- 1 kernigh kernigh 24979 Nov 13 22:15 expression.c
-rw-r--r-- 1 kernigh kernigh 5335 Nov 13 22:15 program.c
-rw-r--r-- 1 kernigh kernigh 29180 Nov 13 22:15 statement.c
-rw------- 1 kernigh kernigh 1728 Nov 13 22:15 tokenfile.c
I seem to have met a bug in em_led (util/led) while trying to get plat/linuxppc to work. With my local changes, I am building linuxppc executables that sometimes crash. One such executable (a modified examples/paranoia.c) had a string at 0x800120cc, but the machine code tries to load it from 0x800020cc. I had compiled it this way:
$ ack -mlinuxppc -o modpar.linuxppc modpar.c
$ ack -mlinuxppc -c.out modpar.c
$ ack -mlinuxppc -c.s modpar.c
By studying modpar.s, I found my string at label _544. By running anm modpar.out
, I found the address: 800120cc 1 - _544
. By running gdb modpar.linuxppc
on the target machine (Debian 8.5 in qemu-system-ppc), gdb disassembled this code:
0x80003d20: 3d 80 80 00 lis r12,-32768
0x80003d24: 61 8c 20 cc ori r12,r12,8396
0x80003d28: 95 81 ff fc stwu r12,-4(r1)
=> 0x80003d2c: 48 00 06 85 bl 0x800043b0
As I had stopped the program there (with break *0x80003d2c
), gdb showed me that $r12 contained 0x800020cc, but I wanted the string at 0x800120cc:
(gdb) print/x $r12
$1 = 0x800020cc
(gdb) print/s (char*)0x800020cc
$2 = 0x800020cc "H"
(gdb) print/s (char*)0x800120cc
$3 = 0x800120cc "Trying to enter the main loop.\n"
This seems to be a bug in em_led: it put the correct address 0x800120cc in the symbol table (as I saw in anm) but the wrong address 0x800020cc in the relocated machine code.
I might not fix this bug. I will try to dodge this bug by loading code at a lower address. plat/powerpc/descr was using -b0:0x80000054
but linux386 and linux68k are already using lower addresses. One might reproduce this bug by using -b0:0x80000054
and putting printf("Some string\n") in paranoia's main(). Strings in 0x8000???? work but strings in 0x8001???? fail, so the problem seems to start around 0x80010000.
Function getpw() in libcc.ansi/misc/getpw.c
in line 27
if(ch = '\0') return 1;
=>
if(ch == '\0') return 1;
should always fclose(pwf) before returning;
I played with mcg in 559233e. I changed plat/linuxppc/descr from ncg to mcg, then rebuilt the ack. (I'm running OpenBSD 6.0 for amd64.) It crashed, as mcg "got signal 11" (SIGSEGV) when compiling something in libcc.ansi. When I looked at the core dump, I found that data_block() in mach/proto/mcg/data.c had taken data pointing to memory shorter than size. I made this change:
diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c
index b66b177..91d90b6 100644
--- a/mach/proto/mcg/parse_em.c
+++ b/mach/proto/mcg/parse_em.c
@@ -237,8 +237,12 @@ static void parse_pseu(void)
}
case str_ptyp:
- data_block(strdup(em.em_string), em.em_size, ro);
+ {
+ void* buf = malloc(em.em_size);
+ memcpy(buf, em.em_string, em.em_size);
+ data_block(buf, em.em_size, ro);
break;
+ }
case cst_ptyp:
data_int(em.em_cst, EM_wordsize, ro);
I guess that the buffer from strdup() was shorter than em.em_size bytes, so I changed it to malloc() and memcpy(). After this change, mcg didn't crash.
Then I ran my tests from https://bitbucket.org/kernigh/ack-ptest with mcg compiling for linuxppc. Some tests failed. I want to report these 3 failures from logic.c:
not ok 6 - six > twelve (2nd)
not ok 18 - negnine > six (2nd)
not ok 42 - !(six < twelve) (2nd)
These failed to be false. Seems that if (a > b)
works, but passing a > b
to a function is broken. I want to have comparisons that work, so we can use them in other tests. It might be time to copy and adapt my logic.c (or something like it) to the tests in plat/tests.
It looks like qemu only loads (or at least, maps) the bottom 4kB of the kernel. So far our tests haven't been big enough to hit this limit, but now we have a big one (written in Modula-2) which is about 20kB, and won't run.
I've turned off qemuppc test running for the time being.
Is there some way the ack can be used to compile minix 2 on any hardware. I'm trying hard to follow the book for minix2 but I want to be able to play with code on a real machine.
Is there an old x86 machine I can buy? I don't know what specific model would work though.
Thanks
Source code is
if (fgets(cp, 1024, fp) == NULL)
return (0);
There is a call to fclose(fp) a few lines later the same function. Why not here ?
PIM defines a low-level I/O and file system access library called FileSystem. See PIM 3rd edition page 178 and PIM 4th edition page 161. I don't have a copy of the 2nd edition at hand but I am dead certain that it is also part of the 2nd edition.
FileSystem is the smallest common denominator for PIM Modula-2. Using FileSystem as a base, it is possible to write portable code across different PIM implementations. InOut alone is insufficient for this purpose because it lacks certain functionality (namely checking if a file exists, delete and rename a file, all of which are essential).
I maintain a portable preprocessor for Modula-2 that is designed to compile on any Modula-2 compiler PIM or ISO.
For this I had to develop techniques and libraries to overcome the differences between the two dialects. In fact the primary purpose of the preprocessor is to allow the writing of portable code and let the preprocessor generate PIM and ISO versions if necessary.
Ironically, when FileSystem is available one can write portably across PIM implementations, but one cannot write portably across ISO Modula-2 implementations, precisely because the ISO standard doesn't provide FileSystem, nor any equivalent, nor any replacement for the missing functionality.
Thus, M2PP uses FileSystem as a base and provides per-compiler adapter libraries for ISO Modula-2 compilers to cover the missing functionality that the ISO standard doesn't provide.
There are eight ISO Modula-2 compilers, so we need eight separate implementations of the FileSystemAdapter library.
I believe a PIM compiler shouldn't require such an adapter. A PIM compiler should provide FileSystem in its library. So should ACK.
When compiling more than one files, it seems that some debug messages are left out, e.g.:
% ack -o test foo.c bar.c
foo.c
bar.c
ACK will be silent if only one file is specified.
FAILED: /home/kernigh/park/ack-build/obj/plat/qemuppc/tests/from_si_to_d_e/stamp
tests/plat/testdriver.sh qemu-system-ppc /home/kernigh/park/ack-build/obj/plat/qemuppc/tests/from_si_to_d_e_bin/from_si_to_d_e_bin 5 && touch /home/kernigh/park/ack-build/obj/plat/qemuppc/tests/from_si_to_d_e/stamp
tests/plat/testdriver.sh[48]: timeout: not found
The build fails just because I run OpenBSD and I haven't installed a timeout command. I'm working around this disabling all the tests: I comment out lines in build.lua so vars.plats_with_tests becomes an empty list.
It seems odd to run the tests during a build. What if a test fails but I still want to build ack? I suggest to move the tests from gmake
to gmake test
.
Source code is
for ( ++cclp; cclflags[cclp] && cclp < lenccl; ++cclp )
Suggest check limit before use not after, like this:
for ( ++cclp; (cclp < lenccl) && cclflags[cclp]; ++cclp )
For following Modula-2 code:
MODULE test;
IMPORT Arguments;
VAR
program: ARRAY [0..1024] OF CHAR;
BEGIN
Arguments.Argv (0, program);
END test.
ACK report following error:
"test.mod", line 9: procedure call expected instead of function call
Which I think should be "function call expected instead of procedure call", as Arguments.Argv
has a return value.
BTW, this message was changed to current form by commit 7f9fd96 in 1988.
In a Forth comment like ( a b c -- d )
, I expect that c was on top of the stack. After commit e7e29d3, comments in powerpc/libem don't match my expectation.
Forth would ignore the comment, but Factor would parse it as a stack effect. The convention from Factor's manual is, "Stack elements in a stack effect are ordered so that the top of the stack is on the right side." So in ( a b c -- d )
, the top is c.
mach/powerpc/libem/rck.s gives the comment ( descriptor value -- )
, but the code seems to load the descriptor from 0(sp) and the value from 4(sp), so the actual stack effect seems to be ( value descriptor -- )
.
libem/ior.s gives the comment ( size b a -- a+b )
, but the actual stack effect seems to be ( b a size -- a+b )
. In contrast, libem/csb.s gives the comment ( value tableaddr -- )
, and the actual stack effect seems to agree with the comment, with tableaddr as top.
Pascal-P5 is a Pascal compiler confirmed to ISO 7185, updated form Pascal-P4.
As I found that Pascal compiler in ACK followed ISO 7185 quite closely, it would be interesting if ACK can be used to bootstrap Pascal-P5.
Currently, following error occurred when compiling pcom.pas
and pint.pas
. It seems that one serious problem is that ACK do not support using subrange as base type of SET, see (pcom.p:L265 and pint.p:L286).
% ack -o pcom pcom.p
"pcom.p", line 265: illegal integer base type of set
"pcom.p", line 276: (warning) old-fashioned syntax ':' missing
"pcom.p", line 535: (warning) old-fashioned syntax ':' missing
"pcom.p", line 539: (warning) old-fashioned syntax ':' missing
"pcom.p", line 788: (warning) "lp" used before set
"pcom.p", line 908: (warning) "m" unused in "strltnvf"
"pcom.p", line 1362: (warning) "i" used before set
"pcom.p", line 3122: "IN": right operand must be a set
"pcom.p", line 3631: (warning) "llev" unused in "pageprocedure"
"pcom.p", line 4413: "+": illegal operand type(s)
"pcom.p", line 4439: "+": illegal operand type(s)
"pcom.p", line 4460: "<>": illegal operand type(s)
% ack -o pint pint.p
"pint.p", line 286: illegal integer base type of set
"pint.p", line 494: (warning) old-fashioned syntax ':' missing
"pint.p", line 513: (warning) old-fashioned syntax ':' missing
"pint.p", line 531: (warning) old-fashioned syntax ':' missing
"pint.p", line 549: (warning) old-fashioned syntax ':' missing
"pint.p", line 587: (warning) old-fashioned syntax ':' missing
"pint.p", line 605: (warning) old-fashioned syntax ':' missing
"pint.p", line 657: (warning) old-fashioned syntax ':' missing
"pint.p", line 675: (warning) old-fashioned syntax ':' missing
"pint.p", line 769: (warning) "ads" unused in "lstins"
"pint.p", line 1385: "+": illegal operand type(s)
"pint.p", line 2599: "=": illegal operand type(s)
"pint.p", line 2607: "<>": illegal operand type(s)
"pint.p", line 2614: ">=": illegal operand type(s)
"pint.p", line 2632: "<=": illegal operand type(s)
"pint.p", line 2676: "IN": right operand must be a set
"pint.p", line 2678: "IN": right operand must be a set
"pint.p", line 2748: "-": illegal operand type(s)
"pint.p", line 2749: "*": illegal operand type(s)
"pint.p", line 2750: "+": illegal operand type(s)
"pint.p", line 2751: "IN": right operand must be a set
"pint.p", line 2894: (warning) "c" unused in "pcode"
"pint.p", line 2894: (warning) "ad3" unused in "pcode"
"pint.p", line 2894: (warning) "option" unused in "pcode"
Hi,
cppcheck found this in function _mid()
[lang/basic/lib/string.c:161]: (error) Uninitialized variable: s2
IMO it is better to return(s) or call error() than to return an uninitialized pointer.
util/ego/cs/cs_profit.c:75]: (warning) fscanf() without field width limits can crash with huge input data.
Source code is
fscanf(f, "%s", s);
maybe better code
fscanf(f, "%100s", s);
mach/proto/ncg/main.c, line 51:
int c = getopt(argc, argv, "-d:D:C:o:");
The '-' in "-d:D:C:o:"
is special to GNU libc or OpenBSD libc, and not portable to some other systems. mcg uses the special '-' to find its input file. I suspect that mcg would fail to find its input file when running on systems like FreeBSD.
The fix would look like my commit 50a7031, where I removed the special '-' from em_b and em_ego. I did not touch mcg because we now don't build mcg.
The current build system (ackbuilder and ninja) is missing some dependences on .h files. When I edit a .h file, the build system fails to rebuild some .c files, and I must do gmake clean
to get a working build.
I edited modules/src/flt_arith/flt_arith.h to reduce the size of a struct. It seems that programs linking to flt_arith (like cemcom.ansi and ncg) depend on flt_arith.h, but the modules/src/flt_arith/*.c files don't depend on flt_arith.h. So gmake
built cemcom.ansi and ncg with the new flt_arith.h but kept flt_arith built with the old flt_arith.h; this caused buffer overflows when cemcom.ansi and ncg allocated the smaller struct but flt_arith wrote the bigger struct. I tried to look for code that would overflow the struct, but the problem was in the build system, not the code.
I run OpenBSD 6.0 for amd64 and use its base gcc to compile ack. I have GNU make 4.2.1 and ninja 1.7.1. The gcc turns on -fstack-protector by default, and this caught overflows from a struct allocated on the stack.
(I am editing flt_arith to look for errors in the conversion of floating-point literals. For example, a literal 0.5 in C code became slightly less than 0.5. This is causing problems with my attempts to test PowerPC floating point.)
It seems that ACK do not support long module names for Modula-2, e.g.:
MODULE test;
IMPORT FooBarBazQux;
BEGIN
END test.
According to strace
output, when compiling this example, ACK will try to open file FooBarBazQ.def
instead of FooBarBazQux.def
.
Can I use ACK to generate raw 8080/8085 or 6800 binary from plain C (no libs)?
A plain binary option for each supported CPU should be possible at least for Intel 8080.
Some vintage computers with 8080 were not CP/M (e.g., Olivetti M 10).
It would be great to be able to generate 6800 because no ANSI C cross compiler exists, yet.
When compiling following code:
MODULE test;
IMPORT Unix;
VAR
r: INTEGER;
BEGIN
r := Unix.execve (NIL, NIL, NIL);
END test.
ACK reports an error:
"test.mod", line 9: (warning) variable "r" never used
Undefined:
_execve
In my pull request #59, @davidgiven reports, "the libem ABI changes break mcg."
I change the ABI in PowerPC libem because I rename some procedures and move some parameters to different locations. I change ncg to use the new ABI, but I don't change mcg. This breaks mcg, because ncg and mcg share the same libem. It remains broken until someone modifies mcg and/or libem to fit together.
We currently don't build mcg by default.
plat/linuxppc/build-tools.lua
commented out the dependency of +tools on +mcg, so it doesn't build mcg for linuxppc.build.lua
commented out qemuppc, so it doesn't enter plat/qemuppc
and doesn't build mcg for qemuppc.They already depend on the language libraries, but not the compilers, which are built by the top-level build.lua --- so there's a race between what gets built first. We should refactor so that each plat depends on all the tools it needs. This would fix the race, and also allow plats to be built one at a time.
Is it sbrk(int) or sbrk(intptr_t)? Our libsys and libcc.ansi use intptr_t, but our libpc and libm2 use int. This will become a problem if we add a platform where int and intptr_t have different sizes.
I have been using OpenBSD's manual pages as a reference. OpenBSD says sbrk(2) takes an int and sets errno = ENOMEM on failure. Some of our libsys implementations don't set errno.
Our ncg tables have broken rules for lor 2, str 2 to load/store the EM heap pointer. These are broken because they don't use sbrk. We only use lor 2, str 2 in the Pascal library, and only for the mark, release keywords. Seems that new, dis got fixed to use sbrk; but mark, release never got fixed.
Our brk() for Linux fails to update the value of sbrk(0).
It seems that calloc() went missing from libcc.ansi after the memory allocator got replaced.
It is not yet possible to build ack on macOS using Apple's compiler. I list some obstacles; there may be other obstacles.
In recent versions of macOS, Apple's compiler is clang. There is a gcc
link that just calls clang. (Some users mistakingly believe that this compiler is gcc. It isn't.)
Right now, clang can't build ack. The problem is that clang makes errors in traditional C code that uses return;
in functions with an implicit int
return type. Such code exists because traditional C had no void
type. I used clang 4.0.0 on OpenBSD 6.2 to build ack from October 2017, but switched to gcc 4.9.4 in February 2018, because the new plat/pdpv7 enabled some traditional C code where clang makes errors.
My old PowerPC machine has Mac OS X 10.4 and Xcode 2.5, where Apple's compiler was gcc 4.2.1, not clang.
Mac filesystems are almost always case-insensitive. This is bug #58 (Does not build on case insensitive filesystems), possibly fixed in commit a1043bc, but no person confirmed that ack now builds on any case-insensitive filesystem.
The sbrk() function in Apple's libc has a limit of only 4 megabytes. If any ack tool uses sbrk(), it might run out of memory.
By default, Apple's archiver doesn't index common symbols in static libraries. This caused a linker error that stopped the build in my old Mac.
I started the build because my old Mac has gcc, not clang. The system's GNU make 3.80 is too old for our top Makefile, so I compiled and used GNU make 4.2.1. (Newer versions of macOS have GNU make 3.81, which might be new enough.) For util/ack, our build system puts the .o files in a static library with ar cqs out.a in.o...
, then links the executable. The symbols from data.c went missing because data.o had only common symbols. So I got a linker error.
The manual says that libtool -c or ranlib -c can index the common symbols. (This manual says so in my old Mac, but also in a newer cctools from https://opensource.apple.com/.) The command would be ar cqS out.a in.o... && ranlib -c out.a
or /usr/bin/libtool -c -static -o out.a in.o...
. The latter must run Apple libtool, not GNU libtool.
I'm running OpenBSD 6.0 for amd64. The build of git fd83b09 fails:
[11/754] ACKDIR=/home/kernigh/park/ack...xamples/hilo_b_linux68k/platstamp -O6
FAILED: /home/kernigh/park/ack-build/obj/examples/hilo_b_linux68k/main/hilo/hilo.o
ACKDIR=/home/kernigh/park/ack-build/staging /home/kernigh/park/ack-build/staging/bin/ack -mlinux68k -c -o /home/kernigh/park/ack-build/obj/examples/hilo_b_linux68k/main/hilo/hilo.o examples/hilo.b -I/home/kernigh/park/ack-build/obj/examples/hilo_b_linux68k/platstamp -O6
/home/kernigh/park/ack-build/staging/bin/ack: warning, No definition for ABC_F
"Ack_167bdf.s", line 359: syntax error
[13/754] ACKDIR=/home/kernigh/park/ack.../cem/libcc.ansi/string/strpbrk.c -O6
ninja: build stopped: subcommand failed.
gmake: *** [Makefile:82: +ack] Error 1
I can reproduce it with the partly-built ack:
$ cd examples
$ ack -mlinux68k -c.o hilo.b -O6
ack: warning, No definition for ABC_F
"Ack_7426f.s", line 359: syntax error
By using -c.s
, I can generate the assembly code. Line 359 is the $Id$ 1f
in
move.l #78,d1
move.l (sp)+,d2
cmp.l d1,d0
$Id$ 1f
bset #0,d2
1:
tst.l d2
beq I6_2
It seems that something goes wrong inside ncg for linux68k, so it outputs $Id$
when it should output a branch instruction.
mach/m68020/as/mach4.c:476]: (style) Expression '(X & 0x38) == 0x1' is always false.
Source code is
if ((mrg_2&070) == 1 && $3!= 02000)
mach/m68020/as/mach4.c:487]: (style) Expression '(X & 0x38) == 0x1' is always false.
Duplicate
I'm running 559233e. I can't assemble this file for PowerPC:
.sect .text
.data4 sz
.sect .rom
be:
.asciz "A string"
sz = . - be
The command ack -mlinuxppc -c.o file.s
fails with "file.s", line 7: expr syntax err
. The commands ack -mlinux386 -c.o file.s
and ack -mlinux68k -c.o file.s
both succeed.
The problem is with the dot .
in the expression . - be
. The assembler defines "." as a DOT token in mach/proto/as/comm3.c, but the PowerPC assembler defines "." as a C token in mach/powerpc/as/mach3.c, so "." appears twice in the keytab. When the assembler searches the keytab, it seems to always find the C "." and never the DOT ".".
C and DOT need to be different tokens, or the yacc grammar would be ambiguous. To fix this problem, one might need to hack the lexer to decide whether each "." is a C or a DOT.
Compile ack default
branch in FreeBSD 10.3 i386 failed with following error:
CPP /tmp/ack-build/obj/i86/mach/proto/as/comm2.y.m
INSTALL /tmp/ack-build/obj/plat/pc86//preprocessed-comm2.y
YACC /tmp/ack-build/obj/plat/pc86//y.tab.c
yacc: 1 shift/reduce conflict.
CC /tmp/ack-build/obj/i86//tmp/ack-build/obj/plat/pc86//y.tab.o
/tmp/ack-build/obj/plat/pc86//preprocessed-comm2.y:96:3: error: conflicting types for '__mbstate_t'
} __mbstate_t;
^
In file included from /usr/local/lib/gcc48/gcc/i386-portbld-freebsd10.1/4.8.5/include-fixed/stdlib.h:47:0,
from /tmp/ack-build/obj/plat/pc86//preprocessed-comm2.y:2:
/usr/include/sys/_types.h:113:3: note: previous declaration of '__mbstate_t' was here
} __mbstate_t;
^
plat/pc86/build.mk:29: recipe for target '/tmp/ack-build/obj/i86//tmp/ack-build/obj/plat/pc86//y.tab.o' failed
gmake: *** [/tmp/ack-build/obj/i86//tmp/ack-build/obj/plat/pc86//y.tab.o] Error 1
I found two bugs in how mcg (commit 4ba409e) compiles plat/linux/libsys/write.c
. The function being compiled is
int write(int fd, void* buffer, size_t count)
{
return _syscall(__NR_write, fd, (quad) buffer, count);
}
The output of ack -mlinuxppc -O6 -c.so write.c
is
.sect .text
.sect .rom
.sect .data
.sect .bss
.extern _write
.sect .text
_write:
! saved_size = 4 bytes
! spills_size = 0 bytes
! locals_size = 0 bytes
addi sp, sp, -12
mfspr r0, lr
stw fp, 4(sp)
stw r0, 8(sp)
addi fp, sp, 4
stw r31, 0(fp)
First bug: The saved r31 overwrites the saved r2. We have allocated 12 bytes of stack space, saved r2 in 4(sp), saved lr in 8(sp), but now save r31 in 4(sp), because addi fp, sp, 4
causes 0(fp) to be the same word as 4(sp).
stw r31, 0(fp)
lwz r12, 16(fp)
lwz r11, 12(fp)
lwz r10, 8(fp)
stwu r12, -4(sp)
stwu r11, -4(sp)
! FROMSI.I(int) -> int
stwu r10, -4(sp)
li32 r12, 4
stwu r12, -4(sp)
bl __syscall
addi sp, sp, 16
! FROMUI.I(int) -> int
mr r3, r31
Second bug: Functions seem to store their return values in r3 but load them from r31. This wrong mr r3, r31
is destroying the return value.
! setret4
.anon_bb_0:
lwz r31, 0(fp)
lwz r0, 4(fp)
mtspr lr, r0
lwz r0, 0(fp)
addi sp, fp, 8
mr fp, r0
bclr 20, 0, 0
This is the first bug again. It's now restoring the caller's r31 from 0(r2) and the caller's r2 from 0(r2), but we lost the value of r2. In my test program, r31 held zero, and r2 held the frame pointer of main(). When main() tried to use the frame pointer, it segfaulted.
Hi,
cppcheck found a memory and a resource leak in readfile()
lang/cem/cemcom/mcomm.c:91
On return the file descriptor fd is leaked and the malloc()ed cbuf.
When I run ./hilo_b.osxppc
, I get an immediate segmentation fault.
$ ./hilo_b.osxppc
Segmentation fault
When I run ./hilo_b.linuxppc
, I get a segmentation fault after I input my name.
$ ./hilo_b.linuxppc
Hi there! I'm written in B. Before we start, what is your name?
> George
Segmentation fault
For this bug report, I built the current master 03386b9 on my OpenBSD/amd64 machine, then copied hilo_b.osxppc
and hilo_b.linuxppc
to the machines that run them. I'm using my PowerBook G4 for OS X and qemu-system-ppc for Linux.
Some symbols have the wrong value. OS X nm
reveals that ioctl
points to the middle of a function in B's library:
$ nm -m hilo_b.osxppc | less
...
00001bd0 t __II8
00001cdc t __II9
00001d28 T _ioctl
00001e20 T _patch_addresses
00001e88 T _main
In gdb, disas isatty
shows that isatty() calls ioctl() at 0x1d28; and disas ioctl
shows the middle of a function. The program crashes because stdio calls isatty() to check if stdout is a tty. Then the program wrongly jumps to 0x1d28 and continues with a corrupt program counter until it crashes.
Linux nm
shows that brk
points outside the program text:
0000001b a EBADGTO
0000003f a EUNIMPL
00001b44 T _brk
10000078 T __m_a_i_n
100000c8 T _i_strcopy
The program doesn't seem to call brk(), so I don't know what causes the crash.
So far, I only have this problem with some B programs on PowerPC. I can reproduce this problem in OS X by simply calling putchar(). Here's the B program:
main()
{
putchar('a');
return (0);
}
Ran ack -mosxppc -o simple simple.b
, copied it to my Mac, then ./simple
segfaulted, again because ioctl
has the wrong value. This program still works in Linux.
I remember that B worked on PowerPC in the past. My recent changes to the assembler or linker might have broken something.
cppcheck reports
lang/cem/cpp.ansi/LLlex.c:265
shifting a 32-bit value (1) by 63 bits (from sizeof(long)) is undefined behavior
and gives a signed integer overflow.
Patch:
arith ubound = ~(1<<(sizeof(arith)*8-1))/(base/2);
=>
arith ubound = ~(1UL<<(sizeof(arith)*8-1))/(base/2);
Probably this was no problem as long as sizeof(int) == sizeof(long)...
Apparently the ACK doesn't work at all on the Itanium, probably because of the 64-bit ints. This is almost certainly due to assumptions about the size of types, and could be related to K&R C with its rather fuzzy type system.
At some point we should investigate why and try to fix it.
I find that current days most Pascal source files are saved with ".pas" extension, it would be nice to make ACK support it.
BTW, does ack
have any option to specifiy compiler directly instead of relying on file name?
It looks like there isn't a way to force a particular source file to be interpreted as a particular language; this is needed if the file has an unexpected extension. We should add one.
The standard seems to be the -x <language>
option, so we should use that.
After my upgrade from qemu 2.10.1 to 2.11.1 (as part of my upgrade from OpenBSD/amd64 6.2 to 6.3), the pc86 tests time out. The test never outputs @@FINISHED
. It outputs @@@@FFIINNIISSHHEED
. Each character appears twice because pc86 writes it to both the VGA console and the serial port, but the emulator now redirects the VGA console to the serial port.
**** /home/kernigh/park/ack-build/obj/plat/pc86/tests/tests/pc86-StringTest_mod-testlog.txt
@@TIMEDOUT
SeaBIOS (version rel-1.11.0-0-g63451fca13-prebuilt.qemu-project.org)
iPXE (http://ipxe.org) 00:03.0 C980 PCI2.10 PnP PMM+07F915A0+07EF15A0 C980
Booting from Hard Disk...
Boot failed: could not read the boot disk
Booting from Floppy...
ACKBOOT
...................
Running.
@@@@FFIINNIISSHHEED
D
Halted.
This seems to be a new feature in SeaBIOS 11.1.0 called "sercon" or server console. The BIOS detects qemu-system-i386 -nographic and redirects the console to serial. I need to remove -nographic to disable the redirection. Then I need to use other options to shut off the graphic display and connect the serial to qemu's stdout. The next diff works for me.
diff --git a/tests/plat/testdriver.sh b/tests/plat/testdriver.sh
index 07f206a5e..76cf79c27 100755
--- a/tests/plat/testdriver.sh
+++ b/tests/plat/testdriver.sh
@@ -22,7 +22,8 @@ get_test_output() {
qemu-system-ppc) img="-kernel $img" ;;
esac
- $timeoutprog -t $timeout -- $method -nographic $img 2>&1
+ $timeoutprog -t $timeout -- $method -display none \
+ -serial mon:stdio $img 2>&1
;;
qemu-*)
Either -serial stdio
or -serial mon:stdio
works. I use -serial mon:stdio to put the QEMU monitor on stdio, because -nographic also does that. The monitor commands are C-a h for help and C-a x to exit qemu.
Line number for unused variable for Modula-2 is not correct, e.g.:
MODULE test;
VAR
i: CARDINAL;
BEGIN
END test.
Output:
"test.mod", line 7: (warning) variable "i" never used/assigned
hilo.mod doesn't work on powerpc platforms. I remember that it worked in the past.
I built f1c357b from the default branch and copied staging/share/ack/examples/hilo_mod.linuxppc to my PowerPC Linux machine (a qemu-system-ppc running Debian). After I enter my name, the program enters an infinite loop until I hit ^C:
kernigh@lip:~$ ./hilo_mod.linuxppc
Hi there! I'm written in Modula-2. Before we start, what is your name?
> George
...
>
Try a bit higher.
>
Try a bit higher.
>
Try a bit higher.
^CSegmentation fault
I built 969e98b from my Mac OS X branch and copied hilo_mod.osxppc to my PowerPC Mac. It has the same problem:
Ghostborough:~/mack kernigh$ ./hilo_mod.osxppc
Hi there! I'm written in Modula-2. Before we start, what is your name?
> George
...
>
Try a bit higher.
>
Try a bit higher.
>
Try a bit higher.
> ^C"lang/m2/libm2/Traps.mod", line 54: got a unix signal
I get a message from Traps.mod in Mac OS X but a "Segmentation fault" in Linux. This might be a bug with signal handlers: Linux puts the signal number in register r3 but ACK reads it from 0(r1).
I also tried hilo_mod.osx386 (from my Mac OS X branch) on an Intel Mac. It doesn't have the bug, so I can guess numbers as usual. I also tried hilo_mod.pc86 (from the default branch) in qemu-system-i386. It doesn't have the bug. I only get the bug with PowerPC.
I expect that (a DIV b) * b + (a MOD b) = a
but our Modula-2 compiler fails me when (a > 0)
and (b < 0)
.
It does 31 DIV (-10) = -4
and 31 MOD (-10) = 9
.
Because 31 ÷ -10 = -3.1, one may round it to -3 or -4.
If it's -3 then (-3 × -10) + 1 = 31.
If it's -4 then (-4 × -10) + -9 = 31.
So the value of 31 MOD (-10)
must be 1 or -9.
It can't be 9.
The compiler forgot to fix the sign from 9 to -9. But if it did fix the sign, then it would still not agree with other Modula-2 compilers.
A document of GNU Modula-2 specifies:
Pim2/3 Pim4 ISO
----------- ----------- ----------------------
lval rval DIV MOD DIV MOD DIV MOD / REM
31 10 3 1 3 1 3 1 3 1
-31 10 -3 -1 -4 9 -4 9 -3 -1
31 -10 -3 1 -3 1 Exception -3 1
-31 -10 3 -1 4 9 Exception 3 -1
I tested MacMETH and ACK and got these results:
MacMETH MacMETH ACK Lua Python
Pim3 Pim4 Pim3 Ruby Tcl
---------- ---------- ---------- ----------
lval rval DIV MOD DIV MOD DIV MOD DIV MOD
31 10 3 1 3 1 3 1 3 1
-31 10 -3 -1 -4 9 -4 9 -4 9
31 -10 -3 1 -3 1 -4 9 -4 -9
-31 -10 3 -1 2 -11 3 -1 3 -1
GNU Modula-2 and MacMETH agree that in Pim3, DIV rounds toward zero and MOD follows sign of 1st operand. (This is like C, awk, bc, and EM.) GNU Modula-2 and MacMETH almost agree about Pim4, except MacMETH strangely has (-31) DIV (-10) = 2
. ACK almost agrees with Lua, Python, Ruby, Tcl, where DIV rounds down and MOD follows sign of 2nd operand.
(MacMETH also raises a compiler error if MOD has a negative operand in a constant expression. I got the above results by using MOD with variables.)
I don't have Pim3 or Pim4, but I checked the draft of Modula-2 Revision 2010 (m2r2010), where DIV rounds up or down such that MOD is always positive. This agrees with GNU-Modula 2 Pim4.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.