tcctok.h: - Add __has_include_next tccpp.c: - New functions parse_include and get_include_file - Changed expr_preprocess and preprocess
Unified · Split
| @@ -1494,8 +1494,98 @@ static void maybe_run_test(TCCState *s) · 1493 unmodified lines | ||
| 1494 | 1494 | define_push(tok, MACRO_OBJ, NULL, NULL); |
| 1495 | 1495 | } |
| 1496 | 1496 | |
| 1497 | +static int parse_include(char *buf, size_t size_buf, int last) | |
| 1498 | +{ | |
| 1499 | + int c; | |
| 1500 | + | |
| 1501 | + skip_spaces(); | |
| 1502 | + if (ch == '<') { | |
| 1503 | + c = '>'; | |
| 1504 | + goto read_name; | |
| 1505 | + } else if (ch == '\"') { | |
| 1506 | + char *q; | |
| 1507 | + | |
| 1508 | + c = ch; | |
| 1509 | + read_name: | |
| 1510 | + inp(); | |
| 1511 | + q = buf; | |
| 1512 | + while (ch != c && ch != '\n' && ch != CH_EOF) { | |
| 1513 | + if ((q - buf) < size_buf - 1) | |
| 1514 | + *q++ = ch; | |
| 1515 | + if (ch == '\\') { | |
| 1516 | + if (handle_stray_noerror() == 0) | |
| 1517 | + --q; | |
| 1518 | + } else | |
| 1519 | + inp(); | |
| 1520 | + } | |
| 1521 | + if (ch != c) | |
| 1522 | + goto error; | |
| 1523 | + *q = '\0'; | |
| 1524 | + minp(); | |
| 1525 | +#if 0 | |
| 1526 | + /* eat all spaces and comments after include */ | |
| 1527 | + /* XXX: slightly incorrect */ | |
| 1528 | + while (ch1 != '\n' && ch1 != CH_EOF) | |
| 1529 | + inp(); | |
| 1530 | +#endif | |
| 1531 | + } else { | |
| 1532 | + int len; | |
| 1533 | + /* computed #include : concatenate everything up to linefeed, | |
| 1534 | + the result must be one of the two accepted forms. | |
| 1535 | + Don't convert pp-tokens to tokens here. */ | |
| 1536 | + parse_flags = (PARSE_FLAG_PREPROCESS | |
| 1537 | + | PARSE_FLAG_LINEFEED | |
| 1538 | + | (parse_flags & PARSE_FLAG_ASM_FILE)); | |
| 1539 | + next(); | |
| 1540 | + buf[0] = '\0'; | |
| 1541 | + while (tok != TOK_LINEFEED && tok != last) { | |
| 1542 | + pstrcat(buf, size_buf, get_tok_str(tok, &tokc)); | |
| 1543 | + next(); | |
| 1544 | + } | |
| 1545 | + len = strlen(buf); | |
| 1546 | + if (tok == last) | |
| 1547 | + unget_tok(0); | |
| 1548 | + /* check syntax and remove '<>|""' */ | |
| 1549 | + if ((len < 2 || ((buf[0] != '"' || buf[len-1] != '"') && | |
| 1550 | + (buf[0] != '<' || buf[len-1] != '>')))) | |
| 1551 | +error: | |
| 1552 | + tcc_error("'#include' expects \"FILENAME\" or <FILENAME>"); | |
| 1553 | + c = buf[len-1]; | |
| 1554 | + memmove(buf, buf + 1, len - 2); | |
| 1555 | + buf[len - 2] = '\0'; | |
| 1556 | + } | |
| 1557 | + return c; | |
| 1558 | +} | |
| 1559 | + | |
| 1560 | +static int get_include_file(TCCState *s1, int i, int c, | |
| 1561 | + char *buf, char *buf1, size_t size_buf1) | |
| 1562 | +{ | |
| 1563 | + const char *path; | |
| 1564 | + | |
| 1565 | + if (i == 0) { | |
| 1566 | + /* check absolute include path */ | |
| 1567 | + if (!IS_ABSPATH(buf)) | |
| 1568 | + return -1; | |
| 1569 | + buf1[0] = 0; | |
| 1570 | + } else if (i == 1) { | |
| 1571 | + /* search in file's dir if "header.h" */ | |
| 1572 | + if (c != '\"') | |
| 1573 | + return -1; | |
| 1574 | + path = file->true_filename; | |
| 1575 | + pstrncpy(buf1, path, tcc_basename(path) - path); | |
| 1576 | + } else { | |
| 1577 | + /* search in all the include paths */ | |
| 1578 | + int j = i - 2, k = j - s1->nb_include_paths; | |
| 1579 | + path = k < 0 ? s1->include_paths[j] : s1->sysinclude_paths[k]; | |
| 1580 | + pstrcpy(buf1, size_buf1, path); | |
| 1581 | + pstrcat(buf1, size_buf1, "/"); | |
| 1582 | + } | |
| 1583 | + pstrcat(buf1, size_buf1, buf); | |
| 1584 | + return 0; | |
| 1585 | +} | |
| 1586 | + | |
| 1497 | 1587 | /* eval an expression for #if/#elif */ |
| 1498 | −static int expr_preprocess(void) | |
| 1588 | +static int expr_preprocess(TCCState *s1) | |
| 1499 | 1589 | { |
| 1500 | 1590 | int c, t; |
| 1501 | 1591 | TokenString *str; |
| @@ -1510,11 +1600,15 @@ static int expr_preprocess(void) · 8 unmodified lines | ||
| 1510 | 1600 | t = tok; |
| 1511 | 1601 | if (t == '(') |
| 1512 | 1602 | next_nomacro(); |
| 1513 | − if (tok < TOK_IDENT) | |
| 1514 | − expect("identifier"); | |
| 1515 | − if (tcc_state->run_test) | |
| 1516 | − maybe_run_test(tcc_state); | |
| 1517 | − c = define_find(tok) != 0; | |
| 1603 | + if (tok == TOK___HAS_INCLUDE || tok == TOK___HAS_INCLUDE_NEXT) | |
| 1604 | + c = 1; | |
| 1605 | + else { | |
| 1606 | + if (tok < TOK_IDENT) | |
| 1607 | + expect("identifier"); | |
| 1608 | + if (tcc_state->run_test) | |
| 1609 | + maybe_run_test(tcc_state); | |
| 1610 | + c = define_find(tok) != 0; | |
| 1611 | + } | |
| 1518 | 1612 | if (t == '(') { |
| 1519 | 1613 | next_nomacro(); |
| 1520 | 1614 | if (tok != ')') |
| @@ -1522,15 +1616,34 @@ static int expr_preprocess(void) · 1 unmodified line | ||
| 1522 | 1616 | } |
| 1523 | 1617 | tok = TOK_CINT; |
| 1524 | 1618 | tokc.i = c; |
| 1525 | − } else if (1 && tok == TOK___HAS_INCLUDE) { | |
| 1526 | − next(); /* XXX check if correct to use expansion */ | |
| 1527 | − skip('('); | |
| 1528 | − while (tok != ')' && tok != TOK_EOF) | |
| 1529 | − next(); | |
| 1619 | + } else if (tok == TOK___HAS_INCLUDE || | |
| 1620 | + tok == TOK___HAS_INCLUDE_NEXT) { | |
| 1621 | + int c, n, i, fd, save_tok = tok; | |
| 1622 | + char buf[1024]; | |
| 1623 | + | |
| 1624 | + next_nomacro(); | |
| 1625 | + if (tok != '(') | |
| 1626 | + expect("("); | |
| 1627 | + ch = file->buf_ptr[0]; | |
| 1628 | + c = parse_include(buf, sizeof(buf), ')'); | |
| 1629 | + next_nomacro(); | |
| 1530 | 1630 | if (tok != ')') |
| 1531 | − expect("')'"); | |
| 1631 | + expect("')'"); | |
| 1532 | 1632 | tok = TOK_CINT; |
| 1533 | 1633 | tokc.i = 0; |
| 1634 | + i = save_tok == TOK___HAS_INCLUDE_NEXT ? file->include_next_index + 1 : 0; | |
| 1635 | + n = 2 + s1->nb_include_paths + s1->nb_sysinclude_paths; | |
| 1636 | + for (; i < n; i++) { | |
| 1637 | + char buf1[sizeof file->filename]; | |
| 1638 | + | |
| 1639 | + if (get_include_file(s1, i, c, buf, buf1, sizeof(buf1))) | |
| 1640 | + continue; | |
| 1641 | + if ((fd = open(buf1, O_RDONLY | O_BINARY)) >= 0) { | |
| 1642 | + close(fd); | |
| 1643 | + tokc.i = 1; | |
| 1644 | + break; | |
| 1645 | + } | |
| 1646 | + } | |
| 1534 | 1647 | } else if (tok >= TOK_IDENT) { |
| 1535 | 1648 | /* if undefined macro, replace with zero, check for func-like */ |
| 1536 | 1649 | t = tok; |
| @@ -1842,55 +1955,8 @@ ST_FUNC void preprocess(int is_bof) · 305 unmodified lines | ||
| 1842 | 1955 | case TOK_INCLUDE_NEXT: |
| 1843 | 1956 | ch = file->buf_ptr[0]; |
| 1844 | 1957 | /* XXX: incorrect if comments : use next_nomacro with a special mode */ |
| 1845 | − skip_spaces(); | |
| 1846 | − if (ch == '<') { | |
| 1847 | − c = '>'; | |
| 1848 | − goto read_name; | |
| 1849 | − } else if (ch == '\"') { | |
| 1850 | − c = ch; | |
| 1851 | − read_name: | |
| 1852 | − inp(); | |
| 1853 | − q = buf; | |
| 1854 | − while (ch != c && ch != '\n' && ch != CH_EOF) { | |
| 1855 | − if ((q - buf) < sizeof(buf) - 1) | |
| 1856 | − *q++ = ch; | |
| 1857 | − if (ch == '\\') { | |
| 1858 | − if (handle_stray_noerror() == 0) | |
| 1859 | − --q; | |
| 1860 | − } else | |
| 1861 | − inp(); | |
| 1862 | − } | |
| 1863 | − *q = '\0'; | |
| 1864 | − minp(); | |
| 1865 | −#if 0 | |
| 1866 | − /* eat all spaces and comments after include */ | |
| 1867 | − /* XXX: slightly incorrect */ | |
| 1868 | − while (ch1 != '\n' && ch1 != CH_EOF) | |
| 1869 | − inp(); | |
| 1870 | −#endif | |
| 1871 | − } else { | |
| 1872 | − int len; | |
| 1873 | − /* computed #include : concatenate everything up to linefeed, | |
| 1874 | − the result must be one of the two accepted forms. | |
| 1875 | − Don't convert pp-tokens to tokens here. */ | |
| 1876 | − parse_flags = (PARSE_FLAG_PREPROCESS | |
| 1877 | − | PARSE_FLAG_LINEFEED | |
| 1878 | − | (parse_flags & PARSE_FLAG_ASM_FILE)); | |
| 1879 | − next(); | |
| 1880 | − buf[0] = '\0'; | |
| 1881 | − while (tok != TOK_LINEFEED) { | |
| 1882 | − pstrcat(buf, sizeof(buf), get_tok_str(tok, &tokc)); | |
| 1883 | − next(); | |
| 1884 | − } | |
| 1885 | − len = strlen(buf); | |
| 1886 | − /* check syntax and remove '<>|""' */ | |
| 1887 | − if ((len < 2 || ((buf[0] != '"' || buf[len-1] != '"') && | |
| 1888 | − (buf[0] != '<' || buf[len-1] != '>')))) | |
| 1889 | − tcc_error("'#include' expects \"FILENAME\" or <FILENAME>"); | |
| 1890 | − c = buf[len-1]; | |
| 1891 | − memmove(buf, buf + 1, len - 2); | |
| 1892 | − buf[len - 2] = '\0'; | |
| 1893 | − } | |
| 1958 | + | |
| 1959 | + c = parse_include(buf, sizeof(buf), 0); | |
| 1894 | 1960 | |
| 1895 | 1961 | if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) |
| 1896 | 1962 | tcc_error("#include recursion too deep"); |
| @@ -1899,31 +1965,9 @@ ST_FUNC void preprocess(int is_bof) · 2 unmodified lines | ||
| 1899 | 1965 | for (; i < n; ++i) { |
| 1900 | 1966 | char buf1[sizeof file->filename]; |
| 1901 | 1967 | CachedInclude *e; |
| 1902 | − const char *path; | |
| 1903 | − | |
| 1904 | − if (i == 0) { | |
| 1905 | − /* check absolute include path */ | |
| 1906 | − if (!IS_ABSPATH(buf)) | |
| 1907 | − continue; | |
| 1908 | − buf1[0] = 0; | |
| 1909 | − | |
| 1910 | − } else if (i == 1) { | |
| 1911 | − /* search in file's dir if "header.h" */ | |
| 1912 | − if (c != '\"') | |
| 1913 | − continue; | |
| 1914 | − /* https://savannah.nongnu.org/bugs/index.php?50847 */ | |
| 1915 | − path = file->true_filename; | |
| 1916 | − pstrncpy(buf1, path, tcc_basename(path) - path); | |
| 1917 | − | |
| 1918 | − } else { | |
| 1919 | − /* search in all the include paths */ | |
| 1920 | − int j = i - 2, k = j - s1->nb_include_paths; | |
| 1921 | − path = k < 0 ? s1->include_paths[j] : s1->sysinclude_paths[k]; | |
| 1922 | − pstrcpy(buf1, sizeof(buf1), path); | |
| 1923 | − pstrcat(buf1, sizeof(buf1), "/"); | |
| 1924 | − } | |
| 1925 | 1968 | |
| 1926 | − pstrcat(buf1, sizeof(buf1), buf); | |
| 1969 | + if (get_include_file(s1, i, c, buf, buf1, sizeof(buf1))) | |
| 1970 | + continue; | |
| 1927 | 1971 | e = search_cached_include(s1, buf1, 0); |
| 1928 | 1972 | if (e && (define_find(e->ifndef_macro) || e->once == pp_once)) { |
| 1929 | 1973 | /* no need to parse the include because the 'ifndef macro' |
| @@ -1965,7 +2009,7 @@ include_done: · 35 unmodified lines | ||
| 1965 | 2009 | c = 1; |
| 1966 | 2010 | goto do_ifdef; |
| 1967 | 2011 | case TOK_IF: |
| 1968 | − c = expr_preprocess(); | |
| 2012 | + c = expr_preprocess(s1); | |
| 1969 | 2013 | goto do_if; |
| 1970 | 2014 | case TOK_IFDEF: |
| 1971 | 2015 | c = 0; |
| @@ -1981,7 +2025,10 @@ include_done: · 9 unmodified lines | ||
| 1981 | 2025 | file->ifndef_macro = tok; |
| 1982 | 2026 | } |
| 1983 | 2027 | } |
| 1984 | − c = (define_find(tok) != 0) ^ c; | |
| 2028 | + if (tok == TOK___HAS_INCLUDE || tok == TOK___HAS_INCLUDE_NEXT) | |
| 2029 | + c = 1 ^ c; | |
| 2030 | + else | |
| 2031 | + c = (define_find(tok) != 0) ^ c; | |
| 1985 | 2032 | do_if: |
| 1986 | 2033 | if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) |
| 1987 | 2034 | tcc_error("memory full (ifdef)"); |
| @@ -2004,7 +2051,7 @@ include_done: · 16 unmodified lines | ||
| 2004 | 2051 | if (c == 1) { |
| 2005 | 2052 | c = 0; |
| 2006 | 2053 | } else { |
| 2007 | − c = expr_preprocess(); | |
| 2054 | + c = expr_preprocess(s1); | |
| 2008 | 2055 | s1->ifdef_stack_ptr[-1] = c; |
| 2009 | 2056 | } |
| 2010 | 2057 | test_else: |
| @@ -94,6 +94,7 @@ · 93 unmodified lines | ||
| 94 | 94 | DEF(TOK___VA_ARGS__, "__VA_ARGS__") |
| 95 | 95 | DEF(TOK___COUNTER__, "__COUNTER__") |
| 96 | 96 | DEF(TOK___HAS_INCLUDE, "__has_include") |
| 97 | + DEF(TOK___HAS_INCLUDE_NEXT, "__has_include_next") | |
| 97 | 98 | |
| 98 | 99 | /* special identifiers */ |
| 99 | 100 | DEF(TOK___FUNC__, "__func__") |